MON Price: $0.018921 (+3.28%)

Contract

0xa13d623405C6Fd7C149fDa7aB463e4DdA399b413

Overview

MON Balance

Monad Chain LogoMonad Chain LogoMonad Chain Logo399.60000000000000585 MON

MON Value

$7.56 (@ $0.02/MON)

Token Holdings

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Prospect Batch393270612025-12-02 3:59:1753 days ago1764647957IN
0xa13d6234...dA399b413
10 MON0.408102
Prospect Batch393270442025-12-02 3:59:1053 days ago1764647950IN
0xa13d6234...dA399b413
28 MON0.408102
Prospect Batch393270282025-12-02 3:59:0453 days ago1764647944IN
0xa13d6234...dA399b413
19 MON0.408102
Prospect Batch393268022025-12-02 3:57:3453 days ago1764647854IN
0xa13d6234...dA399b413
21.1 MON0.408102
Prospect Batch393267852025-12-02 3:57:2753 days ago1764647847IN
0xa13d6234...dA399b413
19.1 MON0.408102
Prospect Batch393267692025-12-02 3:57:2053 days ago1764647840IN
0xa13d6234...dA399b413
27.1 MON0.408102
Prospect Batch393267532025-12-02 3:57:1453 days ago1764647834IN
0xa13d6234...dA399b413
17.1 MON0.408102
Prospect Batch393267372025-12-02 3:57:0753 days ago1764647827IN
0xa13d6234...dA399b413
14.1 MON0.408102
Prospect Batch393267202025-12-02 3:57:0153 days ago1764647821IN
0xa13d6234...dA399b413
17.1 MON0.408102
Set Protocol Vau...392806512025-12-01 22:49:1253 days ago1764629352IN
0xa13d6234...dA399b413
0 MON0.00522348101.84013727
Set Protocol Vau...392806432025-12-01 22:49:0853 days ago1764629348IN
0xa13d6234...dA399b413
0 MON0.00745856101.82201817
Claim Admin Fees392789542025-12-01 22:37:5153 days ago1764628671IN
0xa13d6234...dA399b413
0 MON0.00637919102.01
Claim Mon Only392725812025-12-01 21:55:1853 days ago1764626118IN
0xa13d6234...dA399b413
0 MON0.00833015152.3994
Claim Mon Only392697822025-12-01 21:36:3453 days ago1764624994IN
0xa13d6234...dA399b413
0 MON0.0153102
Claim Mon Only392695242025-12-01 21:34:5153 days ago1764624891IN
0xa13d6234...dA399b413
0 MON0.0153102
Claim Mon Only392695152025-12-01 21:34:4853 days ago1764624888IN
0xa13d6234...dA399b413
0 MON0.0153102
Claim Mon Only392695062025-12-01 21:34:4453 days ago1764624884IN
0xa13d6234...dA399b413
0 MON0.0153102
Claim Mon Only392694972025-12-01 21:34:4053 days ago1764624880IN
0xa13d6234...dA399b413
0 MON0.0153102
Claim Mon Only392694872025-12-01 21:34:3653 days ago1764624876IN
0xa13d6234...dA399b413
0 MON0.0153102
Claim Mon Only392694792025-12-01 21:34:3353 days ago1764624873IN
0xa13d6234...dA399b413
0 MON0.0153102
Claim Mon Only392694702025-12-01 21:34:3053 days ago1764624870IN
0xa13d6234...dA399b413
0 MON0.0153102
Claim Mon Only392694612025-12-01 21:34:2653 days ago1764624866IN
0xa13d6234...dA399b413
0 MON0.0153102
Claim Mon Only392694532025-12-01 21:34:2353 days ago1764624863IN
0xa13d6234...dA399b413
0 MON0.0153102
Claim Mon Only392694432025-12-01 21:34:1953 days ago1764624859IN
0xa13d6234...dA399b413
0 MON0.0153102
Claim Mon Only392694322025-12-01 21:34:1453 days ago1764624854IN
0xa13d6234...dA399b413
0 MON0.0153102
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To
392806432025-12-01 22:49:0853 days ago1764629348
0xa13d6234...dA399b413
15,514.55114928 MON
392789542025-12-01 22:37:5153 days ago1764628671
0xa13d6234...dA399b413
1,551.45511492 MON
392725812025-12-01 21:55:1853 days ago1764626118
0xa13d6234...dA399b413
111.8 MON
392697822025-12-01 21:36:3453 days ago1764624994
0xa13d6234...dA399b413
1,438.64404152 MON
392695242025-12-01 21:34:5153 days ago1764624891
0xa13d6234...dA399b413
1,045.58428473 MON
392695152025-12-01 21:34:4853 days ago1764624888
0xa13d6234...dA399b413
1,602.5252725 MON
392695062025-12-01 21:34:4453 days ago1764624884
0xa13d6234...dA399b413
716.767185 MON
392694972025-12-01 21:34:4053 days ago1764624880
0xa13d6234...dA399b413
866.4718832 MON
392694872025-12-01 21:34:3653 days ago1764624876
0xa13d6234...dA399b413
896.38763055 MON
392694792025-12-01 21:34:3353 days ago1764624873
0xa13d6234...dA399b413
662.17098668 MON
392694702025-12-01 21:34:3053 days ago1764624870
0xa13d6234...dA399b413
1,620.61544673 MON
392694612025-12-01 21:34:2653 days ago1764624866
0xa13d6234...dA399b413
1,969.10018535 MON
392694532025-12-01 21:34:2353 days ago1764624863
0xa13d6234...dA399b413
1,501.16505493 MON
392694432025-12-01 21:34:1953 days ago1764624859
0xa13d6234...dA399b413
789.22216003 MON
392694322025-12-01 21:34:1453 days ago1764624854
0xa13d6234...dA399b413
1,801.28839732 MON
392694232025-12-01 21:34:1153 days ago1764624851
0xa13d6234...dA399b413
1,697.2683383 MON
392694142025-12-01 21:34:0753 days ago1764624847
0xa13d6234...dA399b413
756.71742133 MON
392694052025-12-01 21:34:0353 days ago1764624843
0xa13d6234...dA399b413
1,930.75453765 MON
392693952025-12-01 21:33:5953 days ago1764624839
0xa13d6234...dA399b413
637.50626613 MON
392693862025-12-01 21:33:5653 days ago1764624836
0xa13d6234...dA399b413
740.51867924 MON
392693772025-12-01 21:33:5253 days ago1764624832
0xa13d6234...dA399b413
1,765.13988287 MON
392693682025-12-01 21:33:4953 days ago1764624829
0xa13d6234...dA399b413
1,698.12748152 MON
392693592025-12-01 21:33:4553 days ago1764624825
0xa13d6234...dA399b413
714.54001301 MON
392693502025-12-01 21:33:4153 days ago1764624821
0xa13d6234...dA399b413
811.04786113 MON
392693412025-12-01 21:33:3853 days ago1764624818
0xa13d6234...dA399b413
1,825.90262457 MON
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
CrystalSupply

Compiler Version
v0.8.28+commit.7893614a

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion
File 1 of 11 : CrystalSupply.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@pythnetwork/entropy-sdk-solidity/IEntropyV2.sol";
import "@pythnetwork/entropy-sdk-solidity/IEntropyConsumer.sol";

contract CrystalSupply is Ownable, ReentrancyGuard, IEntropyConsumer {

    IERC20 public immutable crystalToken;

    // Pyth Entropy V2
    IEntropyV2 public immutable entropy;

    // Halving mechanism constants
    uint256 public constant INITIAL_REWARD = 32 ether;
    uint256 public constant HALVING_INTERVAL = 3_000_000 ether;
    uint256 public constant INITIAL_CIRCULATING = 105_000 ether;
    uint256 public constant MAX_HALVINGS = 6;

    uint256 public constant GRID_SIZE = 25;
    uint256 public constant MIN_STAKE = 0.1 ether;

    uint256 public constant REVENUE_FEE_BP = 1100;
    uint256 public constant VAULT_FEE_BP = 1000;
    uint256 public constant ADMIN_FEE_BP = 100;
    uint256 public constant REFINING_FEE_BP = 1000;
    uint256 public KEEPER_FEE = 0.1 ether;
    uint256 public maxAutoCheckpointRounds = 100;

    address public protocolVault;
    address public adminWallet;

    uint256 public pendingAdminFees;
    uint256 public pendingVaultFees;

    uint256 public currentRoundId;
    uint256 public accumulatedTokenPot;
    uint256 public lastRoundStartTime;
    bool public isRolling;

    struct Round {
        uint256 monTotalOfLosingBlocks;
        uint256 monTotalOnWinningBlock;
        uint256 totalRoundStake;
        uint8 winningBlock;
        bool finalized;
        bool motherlodeHit;
        bool isWinnerTakeAll;
        uint256 winningTicket;
        uint256 monPerShare;
        uint256 tokenPerShare;
        uint256 winnerTakeAllTokenAmount;
        uint256 finalizedAt;
        uint256[25] blockTotals;
        uint256[25] minerCounts;
    }

    mapping(uint256 => Round) public rounds;
    mapping(uint256 => mapping(address => mapping(uint8 => uint256))) public userBlockDeposits;
    mapping(uint256 => mapping(address => mapping(uint8 => uint256))) public userCumulativeStart;
    mapping(uint256 => mapping(address => uint256)) public userKeeperFee;

    event Prospect(address indexed user, uint256 roundId, uint8 blockIdx, uint256 amount);
    event RoundEnded(uint256 roundId, uint8 winBlock, bool winnerTakeAll, bool motherlode);
    event CheckpointedByKeeper(address indexed keeper, address indexed user, uint256 roundId, uint256 tokens, uint256 mon, uint256 keeperFee);
    event Claimed(address indexed user, uint256 monAmt, uint256 tokenAmt);
    event RoundStarted(uint256 indexed roundId, uint256 timestamp);
    event KeeperFeeUpdated(uint256 oldFee, uint256 newFee);
    event MaxAutoCheckpointRoundsUpdated(uint256 oldLimit, uint256 newLimit);
    event ProtocolVaultUpdated(address indexed oldVault, address indexed newVault);
    event AdminWalletUpdated(address indexed oldWallet, address indexed newWallet);
    event AdminFeesClaimed(address indexed admin, uint256 amount);
    event VaultFeesClaimed(address indexed vault, uint256 amount);
    event RandomnessRequested(uint256 indexed roundId, uint64 sequenceNumber);

    // Pyth Entropy tracking
    uint64 public currentSequenceNumber;
    mapping(uint64 => uint256) public sequenceToRound;

    uint256 public constant MIN_ROUND_DURATION = 60;
    uint256 public roundDuration = 60;
    uint256 public intermissionDuration = 12; // Configurable intermission for winner reveal
    uint256 public minimumParticipants = 1;
    mapping(uint256 => uint256) public roundParticipantCount;
    mapping(uint256 => mapping(address => bool)) public hasParticipated;
    mapping(uint256 => mapping(uint8 => mapping(address => bool))) public userHasProspectedBlock;
    mapping(uint256 => address[]) public roundParticipants; // Track all participants per round

    uint256 public totalUnclaimedTokens;
    uint256 public minerRewardsFactor;
    uint256 public totalRefinedTokens;
    uint256 public totalSupplyDistributed;  // Tracks TAL distributed for halving calculations
    mapping(address => uint256) public userUnclaimedBalance;
    mapping(address => uint256) public userRewardsFactor;
    mapping(address => uint256) public userRefinedCrystal;
    mapping(uint256 => mapping(address => bool)) public userCreditedRound;
    mapping(address => uint256) public lastCheckpointedRound;
    mapping(address => uint256) public userPendingMon;

    struct CheckpointRequest {
        address user;
        uint256 roundId;
    }
    CheckpointRequest[] public checkpointQueue;
    mapping(address => mapping(uint256 => bool)) public inCheckpointQueue;

    constructor(
        address _entropy,
        address _token,
        address _protocolVault,
        address _adminWallet
    ) Ownable(msg.sender) {
        entropy = IEntropyV2(_entropy);
        crystalToken = IERC20(_token);
        protocolVault = _protocolVault;
        adminWallet = _adminWallet;
        lastRoundStartTime = block.timestamp;
    }
    function getEntropy() internal view override returns (address) {
        return address(entropy);
    }

    function entropyCallback(
        uint64 sequenceNumber,
        address,
        bytes32 randomNumber
    ) internal override {
        uint256 roundId = sequenceToRound[sequenceNumber];
        require(isRolling && roundId == currentRoundId, "Invalid sequence");

        uint256 randomValue = uint256(randomNumber);
        uint256 rwBlock = randomValue;
        uint256 rwMode = uint256(keccak256(abi.encodePacked(randomValue, uint256(1))));
        uint256 rwTicket = uint256(keccak256(abi.encodePacked(randomValue, uint256(2))));

        _finalizeRound(rwBlock, rwMode, rwTicket);

        currentSequenceNumber = 0;
    }

    function setRoundConfig(uint256 _duration, uint256 _minParticipants, uint256 _intermission) external onlyOwner {
        require(_duration >= MIN_ROUND_DURATION, "Too short");
        roundDuration = _duration;
        minimumParticipants = _minParticipants;
        intermissionDuration = _intermission;
    }

    function blockTotalStake(uint256 rId, uint8 blockIdx) external view returns (uint256) {
        return rounds[rId].blockTotals[blockIdx];
    }

    function getUserBalances(address user) external view returns (
        uint256 unclaimed,
        uint256 refined,
        uint256 total
    ) {
        unclaimed = userUnclaimedBalance[user];
        refined = userRefinedCrystal[user];
        if (minerRewardsFactor > userRewardsFactor[user]) {
            uint256 delta = minerRewardsFactor - userRewardsFactor[user];
            uint256 accruedRefined = (delta * unclaimed) / 1e18;
            refined += accruedRefined;
        }
        if (unclaimed > 0 || refined > 0) {
            uint256 fee = (unclaimed * REFINING_FEE_BP) / 10000;
            uint256 netUnclaimed = unclaimed - fee;
            total = netUnclaimed + refined;
        } else {
            total = 0;
        }
        return (unclaimed, refined, total);
    }

    function getEntropyFee() public view returns (uint128) {
        return entropy.getFeeV2();
    }

    /**
     * @notice Calculate current reward per round based on halving schedule
     * @return Current reward amount
     */
    function getCurrentReward() public view returns (uint256) {
        uint256 totalCirculating = INITIAL_CIRCULATING + totalSupplyDistributed;
        uint256 halvings = totalCirculating / HALVING_INTERVAL;

        // Cap at MAX_HALVINGS to prevent underflow
        if (halvings > MAX_HALVINGS) {
            halvings = MAX_HALVINGS;
        }

        // Use bitshift for efficient division by 2^halvings
        return INITIAL_REWARD >> halvings;
    }

    /**
     * @notice Calculate motherlode increment (20% of current reward)
     * @return Motherlode increment amount
     */
    function getMotherlodeInc() public view returns (uint256) {
        return getCurrentReward() / 5;  // 20% of current reward
    }

    function prospect(uint8 blockIdx) external payable nonReentrant {
        require(block.timestamp >= lastRoundStartTime, "Round not started yet (intermission)");
        uint256 rId = isRolling ? currentRoundId + 1 : currentRoundId;
        bool isFirstProspect = (userKeeperFee[rId][msg.sender] == 0);

        if (isFirstProspect) {
            require(msg.value >= MIN_STAKE + KEEPER_FEE, "Send stake + keeper fee");
        } else {
            require(msg.value >= MIN_STAKE, "Min stake");
        }

        _prospect(msg.sender, blockIdx, msg.value, rId);
    }

    function prospectBatch(uint32 blockMask) external payable nonReentrant {
        require(block.timestamp >= lastRoundStartTime, "Round not started yet (intermission)");
        require(msg.value >= MIN_STAKE + KEEPER_FEE, "Send total stake + keeper fee");
        require(blockMask > 0, "No blocks selected");

        uint256 rId = isRolling ? currentRoundId + 1 : currentRoundId;

        uint256 selectedCount = 0;
        uint32 tempMask = blockMask;
        for (uint8 i = 0; i < GRID_SIZE; i++) {
            if (tempMask & 1 == 1) {
                selectedCount++;
            }
            tempMask >>= 1;
        }
        require(selectedCount > 0, "No blocks selected");

        uint256 totalStake = msg.value - KEEPER_FEE;
        uint256 stakePerBlock = totalStake / selectedCount;
        uint256 remainder = totalStake % selectedCount;
        require(stakePerBlock >= MIN_STAKE, "Min per block");

        tempMask = blockMask;
        bool isFirst = true;
        for (uint8 i = 0; i < GRID_SIZE; i++) {
            if (tempMask & 1 == 1) {
                if (isFirst) {
                    _prospect(msg.sender, i, stakePerBlock + KEEPER_FEE + remainder, rId);
                    isFirst = false;
                } else {
                    _prospect(msg.sender, i, stakePerBlock, rId);
                }
            }
            tempMask >>= 1;
        }
    }

    function _prospect(address user, uint8 blockIdx, uint256 amount, uint256 rId) internal {
        require(blockIdx < GRID_SIZE, "Invalid Block");

        uint256 stakeAmount = amount;
        bool isFirstProspect = (userKeeperFee[rId][user] == 0);

        if (isFirstProspect) {
            stakeAmount = amount - KEEPER_FEE;
            userKeeperFee[rId][user] = KEEPER_FEE;
        }

        _prospectInternal(user, blockIdx, stakeAmount, rId);
    }

    function _prospectInternal(address user, uint8 blockIdx, uint256 netAmount, uint256 rId) internal {
        uint256 currentTotal = rounds[rId].blockTotals[blockIdx];

        if (userBlockDeposits[rId][user][blockIdx] == 0) {
            userCumulativeStart[rId][user][blockIdx] = currentTotal;
        }

        userBlockDeposits[rId][user][blockIdx] += netAmount;
        rounds[rId].blockTotals[blockIdx] += netAmount;
        rounds[rId].totalRoundStake += netAmount;

        if (!userHasProspectedBlock[rId][blockIdx][user]) {
            userHasProspectedBlock[rId][blockIdx][user] = true;
            rounds[rId].minerCounts[blockIdx]++;
        }

        if (!hasParticipated[rId][user]) {
            hasParticipated[rId][user] = true;
            roundParticipantCount[rId]++;
            roundParticipants[rId].push(user); // Track participant address
            if (!inCheckpointQueue[user][rId]) {
                inCheckpointQueue[user][rId] = true;
                checkpointQueue.push(CheckpointRequest({user: user, roundId: rId}));
            }
        }

        emit Prospect(user, rId, blockIdx, netAmount);
    }

    function _updateUserRewards(address user) internal {
        if (minerRewardsFactor > userRewardsFactor[user]) {
            uint256 delta = minerRewardsFactor - userRewardsFactor[user];
            uint256 unclaimed = userUnclaimedBalance[user];
            uint256 refined = (delta * unclaimed) / 1e18;
            userRefinedCrystal[user] += refined;
        }
        userRewardsFactor[user] = minerRewardsFactor;
    }

    function _creditUserReward(address user, uint256 amount) internal {
        _updateUserRewards(user);
        userUnclaimedBalance[user] += amount;
        totalUnclaimedTokens += amount;
    }

    function triggerRound() external payable {
        require(block.timestamp >= lastRoundStartTime + roundDuration, "Too early");
        require(!isRolling, "Already rolling");
        require(roundParticipantCount[currentRoundId] >= minimumParticipants, "Not enough participants");

        // Get fee for Pyth Entropy V2 - keeper must pay this
        uint128 fee = entropy.getFeeV2();
        require(msg.value >= fee, "Insufficient entropy fee");

        isRolling = true;

        // Request randomness from Pyth Entropy V2 (no provider/userRandom needed)
        uint64 sequenceNumber = entropy.requestV2{value: fee}();

        currentSequenceNumber = sequenceNumber;
        sequenceToRound[sequenceNumber] = currentRoundId;

        // Refund excess MON to caller
        if (msg.value > fee) {
            (bool success, ) = msg.sender.call{value: msg.value - fee}("");
            require(success, "Refund failed");
        }

        emit RandomnessRequested(currentRoundId, sequenceNumber);
    }

    function _finalizeRound(uint256 rwBlock, uint256 rwMode, uint256 rwTicket) internal {
        Round storage r = rounds[currentRoundId];

        r.winningBlock = uint8(rwBlock % GRID_SIZE);
        r.motherlodeHit = ((rwBlock >> 32) % 625 == 0);
        uint256 winningBlockTotal = r.blockTotals[r.winningBlock];
        r.monTotalOnWinningBlock = winningBlockTotal;
        uint256 roundTotal = r.totalRoundStake;
        uint256 losingMon = roundTotal - winningBlockTotal;
        r.monTotalOfLosingBlocks = losingMon;

        if (winningBlockTotal == 0) {
            uint256 adminFee = (roundTotal * ADMIN_FEE_BP) / 10000;
            pendingAdminFees += adminFee;
            pendingVaultFees += roundTotal - adminFee;
            r.monPerShare = 0;
            r.tokenPerShare = 0;
        } else {
            uint256 adminFee = (losingMon * ADMIN_FEE_BP) / 10000;
            uint256 vaultFee = (losingMon * VAULT_FEE_BP) / 10000;
            uint256 totalFees = adminFee + vaultFee;

            pendingAdminFees += adminFee;
            pendingVaultFees += vaultFee;

            uint256 losingMonAfterFees = losingMon - totalFees;
            r.monPerShare = (losingMonAfterFees * 1e18) / winningBlockTotal;

            // Use dynamic reward based on halving schedule
            uint256 baseReward = getCurrentReward();
            uint256 motherlodeInc = getMotherlodeInc();

            // Accumulate motherlode pot if not hit
            if (!r.motherlodeHit) {
                accumulatedTokenPot += motherlodeInc;
            }

            // Calculate payout
            uint256 payoutToken;
            if (r.motherlodeHit) {
                payoutToken = accumulatedTokenPot + baseReward;
                accumulatedTokenPot = 0;
            } else {
                payoutToken = baseReward;
            }

            // Track total distributed for halving calculations
            totalSupplyDistributed += payoutToken;

            if (rwMode % 2 == 0) {
                r.isWinnerTakeAll = true;
                r.winnerTakeAllTokenAmount = payoutToken;
                r.winningTicket = rwTicket % winningBlockTotal;
            } else {
                r.isWinnerTakeAll = false;
                r.tokenPerShare = (payoutToken * 1e18) / winningBlockTotal;
            }
        }

        r.finalized = true;
        r.finalizedAt = block.timestamp;
        emit RoundEnded(currentRoundId, r.winningBlock, r.isWinnerTakeAll, r.motherlodeHit);

        currentRoundId++;
        lastRoundStartTime = block.timestamp + intermissionDuration;
        isRolling = false;
        emit RoundStarted(currentRoundId, lastRoundStartTime);
    }

    function checkpointUserAuto(address user) external nonReentrant {
        uint256 startRound = lastCheckpointedRound[user] + 1;
        uint256 endRound = currentRoundId;

        if (endRound - startRound > maxAutoCheckpointRounds) {
            endRound = startRound + maxAutoCheckpointRounds;
        }

        uint256 totalKeeperFee = 0;

        for (uint256 rId = startRound; rId < endRound; rId++) {
            Round storage r = rounds[rId];
            if (!r.finalized || userCreditedRound[rId][user]) {
                continue;
            }
            uint256 userStake = userBlockDeposits[rId][user][r.winningBlock];
            if (userStake > 0) {
                uint256 roundTokens = 0;
                if (r.isWinnerTakeAll) {
                    uint256 userStart = userCumulativeStart[rId][user][r.winningBlock];
                    if (r.winningTicket >= userStart && r.winningTicket < userStart + userStake) {
                        roundTokens = r.winnerTakeAllTokenAmount;
                    }
                } else {
                    roundTokens = (userStake * r.tokenPerShare) / 1e18;
                }
                if (roundTokens > 0) {
                    _creditUserReward(user, roundTokens);
                }

                // Calculate and track MON inline to save stack space
                uint256 roundMon = userStake + (userStake * r.monPerShare) / 1e18;
                userPendingMon[user] += roundMon;

                userCreditedRound[rId][user] = true;
                uint256 keeperFee = userKeeperFee[rId][user];
                if (keeperFee > 0) {
                    userKeeperFee[rId][user] = 0;
                    totalKeeperFee += keeperFee;
                    emit CheckpointedByKeeper(msg.sender, user, rId, roundTokens, roundMon, keeperFee);
                } else {
                    emit CheckpointedByKeeper(msg.sender, user, rId, roundTokens, roundMon, 0);
                }
            }
        }
        if (endRound > 0) {
            lastCheckpointedRound[user] = endRound - 1;
        }
        if (totalKeeperFee > 0) {
            payable(msg.sender).transfer(totalKeeperFee);
        }
    }

    function checkpointUser(address user, uint256[] calldata rIds) external nonReentrant {
        uint256 totalKeeperFee = 0;
        for (uint i = 0; i < rIds.length; i++) {
            uint256 rId = rIds[i];
            require(rId < currentRoundId, "Active round");
            Round storage r = rounds[rId];
            require(r.finalized, "Round not finalized");
            if (userCreditedRound[rId][user]) {
                continue;
            }
            uint256 userStake = userBlockDeposits[rId][user][r.winningBlock];
            if (userStake > 0) {
                uint256 roundTokens = 0;
                if (r.isWinnerTakeAll) {
                    uint256 userStart = userCumulativeStart[rId][user][r.winningBlock];
                    if (r.winningTicket >= userStart && r.winningTicket < userStart + userStake) {
                        roundTokens = r.winnerTakeAllTokenAmount;
                    }
                } else {
                    roundTokens = (userStake * r.tokenPerShare) / 1e18;
                }
                if (roundTokens > 0) {
                    _creditUserReward(user, roundTokens);
                }

                // Calculate and track MON inline to save stack space
                uint256 roundMon = userStake + (userStake * r.monPerShare) / 1e18;
                userPendingMon[user] += roundMon;

                userCreditedRound[rId][user] = true;
                uint256 keeperFee = userKeeperFee[rId][user];
                if (keeperFee > 0) {
                    userKeeperFee[rId][user] = 0;
                    totalKeeperFee += keeperFee;
                    emit CheckpointedByKeeper(msg.sender, user, rId, roundTokens, roundMon, keeperFee);
                } else {
                    emit CheckpointedByKeeper(msg.sender, user, rId, roundTokens, roundMon, 0);
                }
            }
        }
        if (totalKeeperFee > 0) {
            payable(msg.sender).transfer(totalKeeperFee);
        }
    }

    function checkpointFromQueue(uint256[] calldata queueIndices) external nonReentrant {
        uint256 totalKeeperFee = 0;
        uint256 queueLen = checkpointQueue.length;

        for (uint i = 0; i < queueIndices.length; i++) {
            uint256 idx = queueIndices[i];
            require(idx < queueLen, "Invalid index");

            if (i > 0) {
                require(queueIndices[i] < queueIndices[i - 1], "Indices must be sorted descending");
            }

            CheckpointRequest memory req = checkpointQueue[idx];
            address user = req.user;
            uint256 rId = req.roundId;

            if (rId >= currentRoundId) continue;
            Round storage r = rounds[rId];
            if (!r.finalized) continue;

            if (userCreditedRound[rId][user]) {
                _removeFromQueue(idx);
                queueLen--;
                continue;
            }

            uint256 userStake = userBlockDeposits[rId][user][r.winningBlock];
            if (userStake > 0) {
                uint256 roundTokens = 0;
                if (r.isWinnerTakeAll) {
                    uint256 userStart = userCumulativeStart[rId][user][r.winningBlock];
                    if (r.winningTicket >= userStart && r.winningTicket < userStart + userStake) {
                        roundTokens = r.winnerTakeAllTokenAmount;
                    }
                } else {
                    roundTokens = (userStake * r.tokenPerShare) / 1e18;
                }
                if (roundTokens > 0) {
                    _creditUserReward(user, roundTokens);
                }

                uint256 roundMon = userStake + (userStake * r.monPerShare) / 1e18;
                userPendingMon[user] += roundMon;

                userCreditedRound[rId][user] = true;
                uint256 keeperFee = userKeeperFee[rId][user];
                if (keeperFee > 0) {
                    userKeeperFee[rId][user] = 0;
                    totalKeeperFee += keeperFee;
                    emit CheckpointedByKeeper(msg.sender, user, rId, roundTokens, roundMon, keeperFee);
                } else {
                    emit CheckpointedByKeeper(msg.sender, user, rId, roundTokens, roundMon, 0);
                }
            }

            _removeFromQueue(idx);
            queueLen--;
        }

        if (totalKeeperFee > 0) {
            payable(msg.sender).transfer(totalKeeperFee);
        }
    }

    function _removeFromQueue(uint256 idx) internal {
        uint256 lastIdx = checkpointQueue.length - 1;
        CheckpointRequest memory removed = checkpointQueue[idx];
        inCheckpointQueue[removed.user][removed.roundId] = false;
        if (idx != lastIdx) {
            checkpointQueue[idx] = checkpointQueue[lastIdx];
        }
        checkpointQueue.pop();
    }


    function claimMonOnly() external nonReentrant {
        uint256 pendingMon = userPendingMon[msg.sender];
        require(pendingMon > 0, "Nothing to claim");

        userPendingMon[msg.sender] = 0;

        (bool s, ) = payable(msg.sender).call{value: pendingMon}("");
        require(s, "Transfer MON failed");

        emit Claimed(msg.sender, pendingMon, 0);
    }

    function claim() external nonReentrant {
        uint256 pendingMon = userPendingMon[msg.sender];

        _updateUserRewards(msg.sender);
        uint256 totalTokens = userUnclaimedBalance[msg.sender];
        uint256 refined = userRefinedCrystal[msg.sender];

        require(pendingMon > 0 || totalTokens > 0 || refined > 0, "Nothing to claim");

        uint256 tokensToTransfer = 0;
        if (totalTokens > 0 || refined > 0) {
            uint256 fee = (totalTokens * REFINING_FEE_BP) / 10000;
            uint256 netTokens = totalTokens - fee;
            if (fee > 0 && totalUnclaimedTokens > totalTokens) {
                uint256 remainingUnclaimed = totalUnclaimedTokens - totalTokens;
                minerRewardsFactor += (fee * 1e18) / remainingUnclaimed;
                totalRefinedTokens += fee;
            }
            userUnclaimedBalance[msg.sender] = 0;
            userRefinedCrystal[msg.sender] = 0;
            totalUnclaimedTokens -= totalTokens;
            tokensToTransfer = netTokens + refined;
        }

        if (pendingMon > 0) {
            userPendingMon[msg.sender] = 0;
            (bool s, ) = payable(msg.sender).call{value: pendingMon}("");
            require(s, "Transfer MON failed");
        }

        if (tokensToTransfer > 0) {
            require(crystalToken.transfer(msg.sender, tokensToTransfer), "Transfer TOK failed");
        }

        emit Claimed(msg.sender, pendingMon, tokensToTransfer);
    }

    function setKeeperFee(uint256 _newFee) external onlyOwner {
        uint256 oldFee = KEEPER_FEE;
        KEEPER_FEE = _newFee;
        emit KeeperFeeUpdated(oldFee, _newFee);
    }

    function setMaxAutoCheckpointRounds(uint256 _newLimit) external onlyOwner {
        require(_newLimit > 0, "Limit must be > 0");
        uint256 oldLimit = maxAutoCheckpointRounds;
        maxAutoCheckpointRounds = _newLimit;
        emit MaxAutoCheckpointRoundsUpdated(oldLimit, _newLimit);
    }

    function setProtocolVault(address _newVault) external onlyOwner {
        require(_newVault != address(0), "Invalid address");
        address oldVault = protocolVault;
        if (pendingVaultFees > 0) {
            uint256 amount = pendingVaultFees;
            pendingVaultFees = 0;
            (bool success, ) = oldVault.call{value: amount}("");
            require(success, "Fee transfer failed");
            emit VaultFeesClaimed(oldVault, amount);
        }
        protocolVault = _newVault;
        emit ProtocolVaultUpdated(oldVault, _newVault);
    }

    function setAdminWallet(address _newWallet) external onlyOwner {
        require(_newWallet != address(0), "Invalid address");
        address oldWallet = adminWallet;
        if (pendingAdminFees > 0) {
            uint256 amount = pendingAdminFees;
            pendingAdminFees = 0;
            (bool success, ) = oldWallet.call{value: amount}("");
            require(success, "Fee transfer failed");
            emit AdminFeesClaimed(oldWallet, amount);
        }
        adminWallet = _newWallet;
        emit AdminWalletUpdated(oldWallet, _newWallet);
    }

    function claimAdminFees() external nonReentrant {
        require(msg.sender == adminWallet, "Not admin");
        uint256 amount = pendingAdminFees;
        require(amount > 0, "No fees to claim");
        pendingAdminFees = 0;
        (bool success, ) = msg.sender.call{value: amount}("");
        require(success, "Transfer failed");
        emit AdminFeesClaimed(msg.sender, amount);
    }

    function claimVaultFees() external nonReentrant {
        require(msg.sender == protocolVault, "Not vault");
        uint256 amount = pendingVaultFees;
        require(amount > 0, "No fees to claim");
        pendingVaultFees = 0;
        (bool success, ) = msg.sender.call{value: amount}("");
        require(success, "Transfer failed");
        emit VaultFeesClaimed(msg.sender, amount);
    }

    function emergencyUnstick() external onlyOwner {
        isRolling = false;
        currentSequenceNumber = 0;
    }

    function getCurrentRoundGrid() external view returns (uint256[25] memory) {
        return rounds[currentRoundId].blockTotals;
    }

    function getCurrentRoundMinerCounts() external view returns (uint256[25] memory) {
        return rounds[currentRoundId].minerCounts;
    }

    function getUserBlockDepositsForRound(uint256 roundId, address user) external view returns (uint256[25] memory) {
        uint256[25] memory deposits;
        for (uint8 i = 0; i < GRID_SIZE; i++) {
            deposits[i] = userBlockDeposits[roundId][user][i];
        }
        return deposits;
    }

    function getCheckpointQueueLength() external view returns (uint256) {
        return checkpointQueue.length;
    }

    function getCheckpointQueue(uint256 offset, uint256 limit) external view returns (
        CheckpointRequest[] memory requests,
        uint256 total
    ) {
        total = checkpointQueue.length;
        if (offset >= total) {
            return (new CheckpointRequest[](0), total);
        }
        uint256 end = offset + limit;
        if (end > total) {
            end = total;
        }
        uint256 count = end - offset;
        requests = new CheckpointRequest[](count);
        for (uint256 i = 0; i < count; i++) {
            requests[i] = checkpointQueue[offset + i];
        }
        return (requests, total);
    }

    function getRoundParticipants(uint256 roundId, uint256 offset, uint256 limit) external view returns (
        address[] memory participants,
        uint256 total
    ) {
        total = roundParticipants[roundId].length;
        if (offset >= total) {
            return (new address[](0), total);
        }
        uint256 end = offset + limit;
        if (end > total) {
            end = total;
        }
        uint256 count = end - offset;
        participants = new address[](count);
        for (uint256 i = 0; i < count; i++) {
            participants[i] = roundParticipants[roundId][offset + i];
        }
        return (participants, total);
    }

    struct WinnerInfo {
        address user;
        uint256 stake;
        uint256 monWon;
        uint256 tokenWon;
    }

    struct RoundWinnersResult {
        WinnerInfo[] winners;
        uint256 totalWinners;
        uint8 winningBlock;
        bool motherlodeHit;
        bool isWinnerTakeAll;
        uint256 finalizedAt;
    }

    function _countWinners(uint256 roundId, uint8 winBlock) internal view returns (uint256 count) {
        uint256 len = roundParticipants[roundId].length;
        for (uint256 i = 0; i < len; i++) {
            if (userBlockDeposits[roundId][roundParticipants[roundId][i]][winBlock] > 0) {
                count++;
            }
        }
    }

    function _calculateWinnerReward(
        uint256 roundId,
        address user,
        uint8 winBlock,
        uint256 stake
    ) internal view returns (uint256 monWon, uint256 tokenWon) {
        Round storage r = rounds[roundId];
        monWon = stake + (stake * r.monPerShare) / 1e18;

        if (r.isWinnerTakeAll) {
            uint256 userStart = userCumulativeStart[roundId][user][winBlock];
            if (r.winningTicket >= userStart && r.winningTicket < userStart + stake) {
                tokenWon = r.winnerTakeAllTokenAmount;
            }
        } else {
            tokenWon = (stake * r.tokenPerShare) / 1e18;
        }
    }

    function getRoundWinners(uint256 roundId, uint256 offset, uint256 limit) external view returns (RoundWinnersResult memory result) {
        Round storage r = rounds[roundId];
        require(r.finalized, "Round not finalized");

        result.winningBlock = r.winningBlock;
        result.motherlodeHit = r.motherlodeHit;
        result.isWinnerTakeAll = r.isWinnerTakeAll;
        result.finalizedAt = r.finalizedAt;

        result.totalWinners = _countWinners(roundId, r.winningBlock);

        if (offset >= result.totalWinners) {
            result.winners = new WinnerInfo[](0);
            return result;
        }

        uint256 end = offset + limit;
        if (end > result.totalWinners) {
            end = result.totalWinners;
        }
        uint256 count = end - offset;
        result.winners = new WinnerInfo[](count);

        uint256 found = 0;
        uint256 collected = 0;
        uint256 len = roundParticipants[roundId].length;

        for (uint256 i = 0; i < len && collected < count; i++) {
            address user = roundParticipants[roundId][i];
            uint256 stake = userBlockDeposits[roundId][user][r.winningBlock];
            if (stake > 0) {
                if (found >= offset) {
                    (uint256 monWon, uint256 tokenWon) = _calculateWinnerReward(roundId, user, r.winningBlock, stake);
                    result.winners[collected] = WinnerInfo(user, stake, monWon, tokenWon);
                    collected++;
                }
                found++;
            }
        }
    }

    struct RoundInfo {
        uint256 totalStake;
        uint8 winningBlock;
        bool finalized;
        bool motherlodeHit;
        bool isWinnerTakeAll;
        uint256 monPerShare;
        uint256 tokenPerShare;
        uint256 winnerTakeAllTokenAmount;
        uint256 finalizedAt;
        uint256 participantCount;
    }

    function getRoundData(uint256 roundId) external view returns (RoundInfo memory info) {
        Round storage r = rounds[roundId];
        info.totalStake = r.totalRoundStake;
        info.winningBlock = r.winningBlock;
        info.finalized = r.finalized;
        info.motherlodeHit = r.motherlodeHit;
        info.isWinnerTakeAll = r.isWinnerTakeAll;
        info.monPerShare = r.monPerShare;
        info.tokenPerShare = r.tokenPerShare;
        info.winnerTakeAllTokenAmount = r.winnerTakeAllTokenAmount;
        info.finalizedAt = r.finalizedAt;
        info.participantCount = roundParticipants[roundId].length;
    }

    receive() external payable {}
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.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 Ownable is Context {
    address private _owner;

    /**
     * @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.
     */
    constructor(address initialOwner) {
        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) {
        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 {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

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

pragma solidity >=0.4.16;

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

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

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

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

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

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

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

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

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

pragma solidity ^0.8.20;

/**
 * @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 Context {
    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;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)

pragma solidity ^0.8.20;

/**
 * @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 EIP-1153 (transient storage) is available on the chain you're deploying at,
 * consider using {ReentrancyGuardTransient} instead.
 *
 * 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 ReentrancyGuard {
    // 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;

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    constructor() {
        _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
        if (_status == ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

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

File 6 of 11 : EntropyEvents.sol
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;

import "./EntropyStructs.sol";

// Deprecated -- these events are still emitted, but the lack of indexing
// makes them hard to use.
interface EntropyEvents {
    event Registered(EntropyStructs.ProviderInfo provider);

    event Requested(EntropyStructs.Request request);
    event RequestedWithCallback(
        address indexed provider,
        address indexed requestor,
        uint64 indexed sequenceNumber,
        bytes32 userRandomNumber,
        EntropyStructs.Request request
    );

    event Revealed(
        EntropyStructs.Request request,
        bytes32 userRevelation,
        bytes32 providerRevelation,
        bytes32 blockHash,
        bytes32 randomNumber
    );
    event RevealedWithCallback(
        EntropyStructs.Request request,
        bytes32 userRandomNumber,
        bytes32 providerRevelation,
        bytes32 randomNumber
    );

    event CallbackFailed(
        address indexed provider,
        address indexed requestor,
        uint64 indexed sequenceNumber,
        bytes32 userRandomNumber,
        bytes32 providerRevelation,
        bytes32 randomNumber,
        bytes errorCode
    );

    event ProviderFeeUpdated(address provider, uint128 oldFee, uint128 newFee);

    event ProviderDefaultGasLimitUpdated(
        address indexed provider,
        uint32 oldDefaultGasLimit,
        uint32 newDefaultGasLimit
    );

    event ProviderUriUpdated(address provider, bytes oldUri, bytes newUri);

    event ProviderFeeManagerUpdated(
        address provider,
        address oldFeeManager,
        address newFeeManager
    );
    event ProviderMaxNumHashesAdvanced(
        address provider,
        uint32 oldMaxNumHashes,
        uint32 newMaxNumHashes
    );

    event Withdrawal(
        address provider,
        address recipient,
        uint128 withdrawnAmount
    );
}

File 7 of 11 : EntropyEventsV2.sol
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;

import "./EntropyStructs.sol";

/**
 * @title EntropyEventsV2
 * @notice Interface defining events for the Entropy V2 system, which handles random number generation
 * and provider management on Ethereum.
 * @dev This interface is used to emit events that track the lifecycle of random number requests,
 * provider registrations, and system configurations.
 */
interface EntropyEventsV2 {
    /**
     * @notice Emitted when a new provider registers with the Entropy system
     * @param provider The address of the registered provider
     * @param extraArgs A field for extra data for forward compatibility.
     */
    event Registered(address indexed provider, bytes extraArgs);

    /**
     * @notice Emitted when a user requests a random number from a provider
     * @param provider The address of the provider handling the request
     * @param caller The address of the user requesting the random number
     * @param sequenceNumber A unique identifier for this request
     * @param userContribution The user's contribution to the random number
     * @param gasLimit The gas limit for the callback.
     * @param extraArgs A field for extra data for forward compatibility.
     */
    event Requested(
        address indexed provider,
        address indexed caller,
        uint64 indexed sequenceNumber,
        bytes32 userContribution,
        uint32 gasLimit,
        bytes extraArgs
    );

    /**
     * @notice Emitted when a provider reveals the generated random number
     * @param provider The address of the provider that generated the random number
     * @param caller The address of the user who requested the random number (and who receives a callback)
     * @param sequenceNumber The unique identifier of the request
     * @param randomNumber The generated random number
     * @param userContribution The user's contribution to the random number
     * @param providerContribution The provider's contribution to the random number
     * @param callbackFailed Whether the callback to the caller failed
     * @param callbackReturnValue Return value from the callback. If the callback failed, this field contains
     * the error code and any additional returned data. Note that "" often indicates an out-of-gas error.
     * If the callback returns more than 256 bytes, only the first 256 bytes of the callback return value are included.
     * @param callbackGasUsed How much gas the callback used.
     * @param extraArgs A field for extra data for forward compatibility.
     */
    event Revealed(
        address indexed provider,
        address indexed caller,
        uint64 indexed sequenceNumber,
        bytes32 randomNumber,
        bytes32 userContribution,
        bytes32 providerContribution,
        bool callbackFailed,
        bytes callbackReturnValue,
        uint32 callbackGasUsed,
        bytes extraArgs
    );

    /**
     * @notice Emitted when a provider updates their fee
     * @param provider The address of the provider updating their fee
     * @param oldFee The previous fee amount
     * @param newFee The new fee amount
     * @param extraArgs A field for extra data for forward compatibility.
     */
    event ProviderFeeUpdated(
        address indexed provider,
        uint128 oldFee,
        uint128 newFee,
        bytes extraArgs
    );

    /**
     * @notice Emitted when a provider updates their default gas limit
     * @param provider The address of the provider updating their gas limit
     * @param oldDefaultGasLimit The previous default gas limit
     * @param newDefaultGasLimit The new default gas limit
     * @param extraArgs A field for extra data for forward compatibility.
     */
    event ProviderDefaultGasLimitUpdated(
        address indexed provider,
        uint32 oldDefaultGasLimit,
        uint32 newDefaultGasLimit,
        bytes extraArgs
    );

    /**
     * @notice Emitted when a provider updates their URI
     * @param provider The address of the provider updating their URI
     * @param oldUri The previous URI
     * @param newUri The new URI
     * @param extraArgs A field for extra data for forward compatibility.
     */
    event ProviderUriUpdated(
        address indexed provider,
        bytes oldUri,
        bytes newUri,
        bytes extraArgs
    );

    /**
     * @notice Emitted when a provider updates their fee manager address
     * @param provider The address of the provider updating their fee manager
     * @param oldFeeManager The previous fee manager address
     * @param newFeeManager The new fee manager address
     * @param extraArgs A field for extra data for forward compatibility.
     */
    event ProviderFeeManagerUpdated(
        address indexed provider,
        address oldFeeManager,
        address newFeeManager,
        bytes extraArgs
    );

    /**
     * @notice Emitted when a provider updates their maximum number of hashes that can be advanced
     * @param provider The address of the provider updating their max hashes
     * @param oldMaxNumHashes The previous maximum number of hashes
     * @param newMaxNumHashes The new maximum number of hashes
     * @param extraArgs A field for extra data for forward compatibility.
     */
    event ProviderMaxNumHashesAdvanced(
        address indexed provider,
        uint32 oldMaxNumHashes,
        uint32 newMaxNumHashes,
        bytes extraArgs
    );

    /**
     * @notice Emitted when a provider withdraws their accumulated fees
     * @param provider The address of the provider withdrawing fees
     * @param recipient The address receiving the withdrawn fees
     * @param withdrawnAmount The amount of fees withdrawn
     * @param extraArgs A field for extra data for forward compatibility.
     */
    event Withdrawal(
        address indexed provider,
        address indexed recipient,
        uint128 withdrawnAmount,
        bytes extraArgs
    );
}

File 8 of 11 : EntropyStructs.sol
// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.0;

// This contract holds old versions of the Entropy structs that are no longer used for contract storage.
// However, they are still used in EntropyEvents to maintain the public interface of prior versions of
// the Entropy contract.
//
// See EntropyStructsV2 for the struct definitions currently in use.
contract EntropyStructs {
    struct ProviderInfo {
        uint128 feeInWei;
        uint128 accruedFeesInWei;
        // The commitment that the provider posted to the blockchain, and the sequence number
        // where they committed to this. This value is not advanced after the provider commits,
        // and instead is stored to help providers track where they are in the hash chain.
        bytes32 originalCommitment;
        uint64 originalCommitmentSequenceNumber;
        // Metadata for the current commitment. Providers may optionally use this field to help
        // manage rotations (i.e., to pick the sequence number from the correct hash chain).
        bytes commitmentMetadata;
        // Optional URI where clients can retrieve revelations for the provider.
        // Client SDKs can use this field to automatically determine how to retrieve random values for each provider.
        // TODO: specify the API that must be implemented at this URI
        bytes uri;
        // The first sequence number that is *not* included in the current commitment (i.e., an exclusive end index).
        // The contract maintains the invariant that sequenceNumber <= endSequenceNumber.
        // If sequenceNumber == endSequenceNumber, the provider must rotate their commitment to add additional random values.
        uint64 endSequenceNumber;
        // The sequence number that will be assigned to the next inbound user request.
        uint64 sequenceNumber;
        // The current commitment represents an index/value in the provider's hash chain.
        // These values are used to verify requests for future sequence numbers. Note that
        // currentCommitmentSequenceNumber < sequenceNumber.
        //
        // The currentCommitment advances forward through the provider's hash chain as values
        // are revealed on-chain.
        bytes32 currentCommitment;
        uint64 currentCommitmentSequenceNumber;
        // An address that is authorized to set / withdraw fees on behalf of this provider.
        address feeManager;
        // Maximum number of hashes to record in a request. This should be set according to the maximum gas limit
        // the provider supports for callbacks.
        uint32 maxNumHashes;
    }

    struct Request {
        // Storage slot 1 //
        address provider;
        uint64 sequenceNumber;
        // The number of hashes required to verify the provider revelation.
        uint32 numHashes;
        // Storage slot 2 //
        // The commitment is keccak256(userCommitment, providerCommitment). Storing the hash instead of both saves 20k gas by
        // eliminating 1 store.
        bytes32 commitment;
        // Storage slot 3 //
        // The number of the block where this request was created.
        // Note that we're using a uint64 such that we have an additional space for an address and other fields in
        // this storage slot. Although block.number returns a uint256, 64 bits should be plenty to index all of the
        // blocks ever generated.
        uint64 blockNumber;
        // The address that requested this random number.
        address requester;
        // If true, incorporate the blockhash of blockNumber into the generated random value.
        bool useBlockhash;
        // True if this is a request that expects a callback.
        bool isRequestWithCallback;
    }
}

File 9 of 11 : EntropyStructsV2.sol
// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.0;

contract EntropyStructsV2 {
    struct ProviderInfo {
        uint128 feeInWei;
        uint128 accruedFeesInWei;
        // The commitment that the provider posted to the blockchain, and the sequence number
        // where they committed to this. This value is not advanced after the provider commits,
        // and instead is stored to help providers track where they are in the hash chain.
        bytes32 originalCommitment;
        uint64 originalCommitmentSequenceNumber;
        // Metadata for the current commitment. Providers may optionally use this field to help
        // manage rotations (i.e., to pick the sequence number from the correct hash chain).
        bytes commitmentMetadata;
        // Optional URI where clients can retrieve revelations for the provider.
        // Client SDKs can use this field to automatically determine how to retrieve random values for each provider.
        // TODO: specify the API that must be implemented at this URI
        bytes uri;
        // The first sequence number that is *not* included in the current commitment (i.e., an exclusive end index).
        // The contract maintains the invariant that sequenceNumber <= endSequenceNumber.
        // If sequenceNumber == endSequenceNumber, the provider must rotate their commitment to add additional random values.
        uint64 endSequenceNumber;
        // The sequence number that will be assigned to the next inbound user request.
        uint64 sequenceNumber;
        // The current commitment represents an index/value in the provider's hash chain.
        // These values are used to verify requests for future sequence numbers. Note that
        // currentCommitmentSequenceNumber < sequenceNumber.
        //
        // The currentCommitment advances forward through the provider's hash chain as values
        // are revealed on-chain.
        bytes32 currentCommitment;
        uint64 currentCommitmentSequenceNumber;
        // An address that is authorized to set / withdraw fees on behalf of this provider.
        address feeManager;
        // Maximum number of hashes to record in a request. This should be set according to the maximum gas limit
        // the provider supports for callbacks.
        uint32 maxNumHashes;
        // Default gas limit to use for callbacks.
        uint32 defaultGasLimit;
    }

    struct Request {
        // Storage slot 1 //
        address provider;
        uint64 sequenceNumber;
        // The number of hashes required to verify the provider revelation.
        uint32 numHashes;
        // Storage slot 2 //
        // The commitment is keccak256(userCommitment, providerCommitment). Storing the hash instead of both saves 20k gas by
        // eliminating 1 store.
        bytes32 commitment;
        // Storage slot 3 //
        // The number of the block where this request was created.
        // Note that we're using a uint64 such that we have an additional space for an address and other fields in
        // this storage slot. Although block.number returns a uint256, 64 bits should be plenty to index all of the
        // blocks ever generated.
        uint64 blockNumber;
        // The address that requested this random number.
        address requester;
        // If true, incorporate the blockhash of blockNumber into the generated random value.
        bool useBlockhash;
        // Status flag for requests with callbacks. See EntropyConstants for the possible values of this flag.
        uint8 callbackStatus;
        // The gasLimit in units of 10k gas. (i.e., 2 = 20k gas). We're using units of 10k in order to fit this
        // field into the remaining 2 bytes of this storage slot. The dynamic range here is 10k - 655M, which should
        // cover all real-world use cases.
        uint16 gasLimit10k;
    }
}

// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;

abstract contract IEntropyConsumer {
    // This method is called by Entropy to provide the random number to the consumer.
    // It asserts that the msg.sender is the Entropy contract. It is not meant to be
    // override by the consumer.
    function _entropyCallback(
        uint64 sequence,
        address provider,
        bytes32 randomNumber
    ) external {
        address entropy = getEntropy();
        require(entropy != address(0), "Entropy address not set");
        require(msg.sender == entropy, "Only Entropy can call this function");

        entropyCallback(sequence, provider, randomNumber);
    }

    // getEntropy returns Entropy contract address. The method is being used to check that the
    // callback is indeed from Entropy contract. The consumer is expected to implement this method.
    // Entropy address can be found here - https://docs.pyth.network/entropy/contract-addresses
    function getEntropy() internal view virtual returns (address);

    // This method is expected to be implemented by the consumer to handle the random number.
    // It will be called by _entropyCallback after _entropyCallback ensures that the call is
    // indeed from Entropy contract.
    function entropyCallback(
        uint64 sequence,
        address provider,
        bytes32 randomNumber
    ) internal virtual;
}

// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;

import "./EntropyEvents.sol";
import "./EntropyEventsV2.sol";
import "./EntropyStructsV2.sol";

interface IEntropyV2 is EntropyEventsV2 {
    /// @notice Request a random number using the default provider with default gas limit
    /// @return assignedSequenceNumber A unique identifier for this request
    /// @dev The address calling this function should be a contract that inherits from the IEntropyConsumer interface.
    /// The `entropyCallback` method on that interface will receive a callback with the returned sequence number and
    /// the generated random number.
    ///
    /// `entropyCallback` will be run with the provider's configured default gas limit.
    ///
    /// This method will revert unless the caller provides a sufficient fee (at least `getFeeV2()`) as msg.value.
    /// Note that the fee can change over time. Callers of this method should explicitly compute `getFeeV2()`
    /// prior to each invocation (as opposed to hardcoding a value). Further note that excess value is *not* refunded to the caller.
    ///
    /// Note that this method uses an in-contract PRNG to generate the user's contribution to the random number.
    /// This approach modifies the security guarantees such that a dishonest validator and provider can
    /// collude to manipulate the result (as opposed to a malicious user and provider). That is, the user
    /// now trusts the validator honestly draw a random number. If you wish to avoid this trust assumption,
    /// call a variant of `requestV2` that accepts a `userRandomNumber` parameter.
    function requestV2()
        external
        payable
        returns (uint64 assignedSequenceNumber);

    /// @notice Request a random number using the default provider with specified gas limit
    /// @param gasLimit The gas limit for the callback function.
    /// @return assignedSequenceNumber A unique identifier for this request
    /// @dev The address calling this function should be a contract that inherits from the IEntropyConsumer interface.
    /// The `entropyCallback` method on that interface will receive a callback with the returned sequence number and
    /// the generated random number.
    ///
    /// `entropyCallback` will be run with the `gasLimit` provided to this function.
    /// The `gasLimit` will be rounded up to a multiple of 10k (e.g., 19000 -> 20000), and furthermore is lower bounded
    /// by the provider's configured default limit.
    ///
    /// This method will revert unless the caller provides a sufficient fee (at least `getFeeV2(gasLimit)`) as msg.value.
    /// Note that the fee can change over time. Callers of this method should explicitly compute `getFeeV2(gasLimit)`
    /// prior to each invocation (as opposed to hardcoding a value). Further note that excess value is *not* refunded to the caller.
    ///
    /// Note that this method uses an in-contract PRNG to generate the user's contribution to the random number.
    /// This approach modifies the security guarantees such that a dishonest validator and provider can
    /// collude to manipulate the result (as opposed to a malicious user and provider). That is, the user
    /// now trusts the validator honestly draw a random number. If you wish to avoid this trust assumption,
    /// call a variant of `requestV2` that accepts a `userRandomNumber` parameter.
    function requestV2(
        uint32 gasLimit
    ) external payable returns (uint64 assignedSequenceNumber);

    /// @notice Request a random number from a specific provider with specified gas limit
    /// @param provider The address of the provider to request from
    /// @param gasLimit The gas limit for the callback function
    /// @return assignedSequenceNumber A unique identifier for this request
    /// @dev The address calling this function should be a contract that inherits from the IEntropyConsumer interface.
    /// The `entropyCallback` method on that interface will receive a callback with the returned sequence number and
    /// the generated random number.
    ///
    /// `entropyCallback` will be run with the `gasLimit` provided to this function.
    /// The `gasLimit` will be rounded up to a multiple of 10k (e.g., 19000 -> 20000), and furthermore is lower bounded
    /// by the provider's configured default limit.
    ///
    /// This method will revert unless the caller provides a sufficient fee (at least `getFeeV2(provider, gasLimit)`) as msg.value.
    /// Note that provider fees can change over time. Callers of this method should explicitly compute `getFeeV2(provider, gasLimit)`
    /// prior to each invocation (as opposed to hardcoding a value). Further note that excess value is *not* refunded to the caller.
    ///
    /// Note that this method uses an in-contract PRNG to generate the user's contribution to the random number.
    /// This approach modifies the security guarantees such that a dishonest validator and provider can
    /// collude to manipulate the result (as opposed to a malicious user and provider). That is, the user
    /// now trusts the validator honestly draw a random number. If you wish to avoid this trust assumption,
    /// call a variant of `requestV2` that accepts a `userRandomNumber` parameter.
    function requestV2(
        address provider,
        uint32 gasLimit
    ) external payable returns (uint64 assignedSequenceNumber);

    /// @notice Request a random number from a specific provider with a user-provided random number and gas limit
    /// @param provider The address of the provider to request from
    /// @param userRandomNumber A random number provided by the user for additional entropy
    /// @param gasLimit The gas limit for the callback function. Pass 0 to get a sane default value -- see note below.
    /// @return assignedSequenceNumber A unique identifier for this request
    /// @dev The address calling this function should be a contract that inherits from the IEntropyConsumer interface.
    /// The `entropyCallback` method on that interface will receive a callback with the returned sequence number and
    /// the generated random number.
    ///
    /// `entropyCallback` will be run with the `gasLimit` provided to this function.
    /// The `gasLimit` will be rounded up to a multiple of 10k (e.g., 19000 -> 20000), and furthermore is lower bounded
    /// by the provider's configured default limit.
    ///
    /// This method will revert unless the caller provides a sufficient fee (at least `getFeeV2(provider, gasLimit)`) as msg.value.
    /// Note that provider fees can change over time. Callers of this method should explicitly compute `getFeeV2(provider, gasLimit)`
    /// prior to each invocation (as opposed to hardcoding a value). Further note that excess value is *not* refunded to the caller.
    function requestV2(
        address provider,
        bytes32 userRandomNumber,
        uint32 gasLimit
    ) external payable returns (uint64 assignedSequenceNumber);

    /// @notice Get information about a specific entropy provider
    /// @param provider The address of the provider to query
    /// @return info The provider information including configuration, fees, and operational status
    /// @dev This method returns detailed information about a provider's configuration and capabilities.
    /// The returned ProviderInfo struct contains information such as the provider's fee structure and gas limits.
    function getProviderInfoV2(
        address provider
    ) external view returns (EntropyStructsV2.ProviderInfo memory info);

    /// @notice Get the address of the default entropy provider
    /// @return provider The address of the default provider
    /// @dev This method returns the address of the provider that will be used when no specific provider is specified
    /// in the requestV2 calls. The default provider can be used to get the base fee and gas limit information.
    function getDefaultProvider() external view returns (address provider);

    /// @notice Get information about a specific request
    /// @param provider The address of the provider that handled the request
    /// @param sequenceNumber The unique identifier of the request
    /// @return req The request information including status, random number, and other metadata
    /// @dev This method allows querying the state of a previously made request. The returned Request struct
    /// contains information about whether the request was fulfilled, the generated random number (if available),
    /// and other metadata about the request.
    function getRequestV2(
        address provider,
        uint64 sequenceNumber
    ) external view returns (EntropyStructsV2.Request memory req);

    /// @notice Get the fee charged by the default provider for the default gas limit
    /// @return feeAmount The fee amount in wei
    /// @dev This method returns the base fee required to make a request using the default provider with
    /// the default gas limit. This fee should be passed as msg.value when calling requestV2().
    /// The fee can change over time, so this method should be called before each request.
    function getFeeV2() external view returns (uint128 feeAmount);

    /// @notice Get the fee charged by the default provider for a specific gas limit
    /// @param gasLimit The gas limit for the callback function
    /// @return feeAmount The fee amount in wei
    /// @dev This method returns the fee required to make a request using the default provider with
    /// the specified gas limit. This fee should be passed as msg.value when calling requestV2(gasLimit).
    /// The fee can change over time, so this method should be called before each request.
    function getFeeV2(
        uint32 gasLimit
    ) external view returns (uint128 feeAmount);

    /// @notice Get the fee charged by a specific provider for a request with a given gas limit
    /// @param provider The address of the provider to query
    /// @param gasLimit The gas limit for the callback function
    /// @return feeAmount The fee amount in wei
    /// @dev This method returns the fee required to make a request using the specified provider with
    /// the given gas limit. This fee should be passed as msg.value when calling requestV2(provider, gasLimit)
    /// or requestV2(provider, userRandomNumber, gasLimit). The fee can change over time, so this method
    /// should be called before each request.
    function getFeeV2(
        address provider,
        uint32 gasLimit
    ) external view returns (uint128 feeAmount);
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "viaIR": false,
  "evmVersion": "paris",
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_entropy","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_protocolVault","type":"address"},{"internalType":"address","name":"_adminWallet","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"admin","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"AdminFeesClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldWallet","type":"address"},{"indexed":true,"internalType":"address","name":"newWallet","type":"address"}],"name":"AdminWalletUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"keeper","type":"address"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"roundId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokens","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mon","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"keeperFee","type":"uint256"}],"name":"CheckpointedByKeeper","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"monAmt","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenAmt","type":"uint256"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFee","type":"uint256"}],"name":"KeeperFeeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldLimit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newLimit","type":"uint256"}],"name":"MaxAutoCheckpointRoundsUpdated","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":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"roundId","type":"uint256"},{"indexed":false,"internalType":"uint8","name":"blockIdx","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Prospect","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldVault","type":"address"},{"indexed":true,"internalType":"address","name":"newVault","type":"address"}],"name":"ProtocolVaultUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"roundId","type":"uint256"},{"indexed":false,"internalType":"uint64","name":"sequenceNumber","type":"uint64"}],"name":"RandomnessRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"roundId","type":"uint256"},{"indexed":false,"internalType":"uint8","name":"winBlock","type":"uint8"},{"indexed":false,"internalType":"bool","name":"winnerTakeAll","type":"bool"},{"indexed":false,"internalType":"bool","name":"motherlode","type":"bool"}],"name":"RoundEnded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"roundId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"RoundStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"VaultFeesClaimed","type":"event"},{"inputs":[],"name":"ADMIN_FEE_BP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GRID_SIZE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"HALVING_INTERVAL","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"INITIAL_CIRCULATING","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"INITIAL_REWARD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"KEEPER_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_HALVINGS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_ROUND_DURATION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_STAKE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFINING_FEE_BP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REVENUE_FEE_BP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VAULT_FEE_BP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"sequence","type":"uint64"},{"internalType":"address","name":"provider","type":"address"},{"internalType":"bytes32","name":"randomNumber","type":"bytes32"}],"name":"_entropyCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"accumulatedTokenPot","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"adminWallet","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"rId","type":"uint256"},{"internalType":"uint8","name":"blockIdx","type":"uint8"}],"name":"blockTotalStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"queueIndices","type":"uint256[]"}],"name":"checkpointFromQueue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"checkpointQueue","outputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roundId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256[]","name":"rIds","type":"uint256[]"}],"name":"checkpointUser","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"checkpointUserAuto","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimAdminFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimMonOnly","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimVaultFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"crystalToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentRoundId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentSequenceNumber","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"emergencyUnstick","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"entropy","outputs":[{"internalType":"contract IEntropyV2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"offset","type":"uint256"},{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"getCheckpointQueue","outputs":[{"components":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roundId","type":"uint256"}],"internalType":"struct CrystalSupply.CheckpointRequest[]","name":"requests","type":"tuple[]"},{"internalType":"uint256","name":"total","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCheckpointQueueLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentRoundGrid","outputs":[{"internalType":"uint256[25]","name":"","type":"uint256[25]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentRoundMinerCounts","outputs":[{"internalType":"uint256[25]","name":"","type":"uint256[25]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getEntropyFee","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMotherlodeInc","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"roundId","type":"uint256"}],"name":"getRoundData","outputs":[{"components":[{"internalType":"uint256","name":"totalStake","type":"uint256"},{"internalType":"uint8","name":"winningBlock","type":"uint8"},{"internalType":"bool","name":"finalized","type":"bool"},{"internalType":"bool","name":"motherlodeHit","type":"bool"},{"internalType":"bool","name":"isWinnerTakeAll","type":"bool"},{"internalType":"uint256","name":"monPerShare","type":"uint256"},{"internalType":"uint256","name":"tokenPerShare","type":"uint256"},{"internalType":"uint256","name":"winnerTakeAllTokenAmount","type":"uint256"},{"internalType":"uint256","name":"finalizedAt","type":"uint256"},{"internalType":"uint256","name":"participantCount","type":"uint256"}],"internalType":"struct CrystalSupply.RoundInfo","name":"info","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"roundId","type":"uint256"},{"internalType":"uint256","name":"offset","type":"uint256"},{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"getRoundParticipants","outputs":[{"internalType":"address[]","name":"participants","type":"address[]"},{"internalType":"uint256","name":"total","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"roundId","type":"uint256"},{"internalType":"uint256","name":"offset","type":"uint256"},{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"getRoundWinners","outputs":[{"components":[{"components":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"stake","type":"uint256"},{"internalType":"uint256","name":"monWon","type":"uint256"},{"internalType":"uint256","name":"tokenWon","type":"uint256"}],"internalType":"struct CrystalSupply.WinnerInfo[]","name":"winners","type":"tuple[]"},{"internalType":"uint256","name":"totalWinners","type":"uint256"},{"internalType":"uint8","name":"winningBlock","type":"uint8"},{"internalType":"bool","name":"motherlodeHit","type":"bool"},{"internalType":"bool","name":"isWinnerTakeAll","type":"bool"},{"internalType":"uint256","name":"finalizedAt","type":"uint256"}],"internalType":"struct CrystalSupply.RoundWinnersResult","name":"result","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserBalances","outputs":[{"internalType":"uint256","name":"unclaimed","type":"uint256"},{"internalType":"uint256","name":"refined","type":"uint256"},{"internalType":"uint256","name":"total","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"roundId","type":"uint256"},{"internalType":"address","name":"user","type":"address"}],"name":"getUserBlockDepositsForRound","outputs":[{"internalType":"uint256[25]","name":"","type":"uint256[25]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"hasParticipated","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"inCheckpointQueue","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"intermissionDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isRolling","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"lastCheckpointedRound","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastRoundStartTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxAutoCheckpointRounds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minerRewardsFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minimumParticipants","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingAdminFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingVaultFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"blockIdx","type":"uint8"}],"name":"prospect","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint32","name":"blockMask","type":"uint32"}],"name":"prospectBatch","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"protocolVault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"roundDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"roundParticipantCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"roundParticipants","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rounds","outputs":[{"internalType":"uint256","name":"monTotalOfLosingBlocks","type":"uint256"},{"internalType":"uint256","name":"monTotalOnWinningBlock","type":"uint256"},{"internalType":"uint256","name":"totalRoundStake","type":"uint256"},{"internalType":"uint8","name":"winningBlock","type":"uint8"},{"internalType":"bool","name":"finalized","type":"bool"},{"internalType":"bool","name":"motherlodeHit","type":"bool"},{"internalType":"bool","name":"isWinnerTakeAll","type":"bool"},{"internalType":"uint256","name":"winningTicket","type":"uint256"},{"internalType":"uint256","name":"monPerShare","type":"uint256"},{"internalType":"uint256","name":"tokenPerShare","type":"uint256"},{"internalType":"uint256","name":"winnerTakeAllTokenAmount","type":"uint256"},{"internalType":"uint256","name":"finalizedAt","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"","type":"uint64"}],"name":"sequenceToRound","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newWallet","type":"address"}],"name":"setAdminWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newFee","type":"uint256"}],"name":"setKeeperFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newLimit","type":"uint256"}],"name":"setMaxAutoCheckpointRounds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newVault","type":"address"}],"name":"setProtocolVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_duration","type":"uint256"},{"internalType":"uint256","name":"_minParticipants","type":"uint256"},{"internalType":"uint256","name":"_intermission","type":"uint256"}],"name":"setRoundConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalRefinedTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupplyDistributed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalUnclaimedTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"triggerRound","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint8","name":"","type":"uint8"}],"name":"userBlockDeposits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"userCreditedRound","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint8","name":"","type":"uint8"}],"name":"userCumulativeStart","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint8","name":"","type":"uint8"},{"internalType":"address","name":"","type":"address"}],"name":"userHasProspectedBlock","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"userKeeperFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userPendingMon","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userRefinedCrystal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userRewardsFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userUnclaimedBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

60c060405267016345785d8a00006002556064600355603c601255600c601355600160145534801561003057600080fd5b5060405161515e38038061515e83398101604081905261004f9161012f565b338061007557604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b61007e816100c3565b50600180556001600160a01b0393841660a052918316608052600480549184166001600160a01b03199283161790556005805492909316911617905542600a55610183565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80516001600160a01b038116811461012a57600080fd5b919050565b6000806000806080858703121561014557600080fd5b61014e85610113565b935061015c60208601610113565b925061016a60408601610113565b915061017860608601610113565b905092959194509250565b60805160a051614f936101cb600039600081816106bc0152818161115a01528181611cf20152818161294c0152612a51015260008181610e2e0152611bf10152614f936000f3fe6080604052600436106104825760003560e01c80638aec854211610255578063c9fbcfb011610144578063f0f2f6ee116100c1578063fbb098ee11610085578063fbb098ee14610f35578063fc44e4c714610f4b578063fc89aeaa14610f84578063fcfd837f14610fa4578063fd5c0cc614610fb9578063fe31a61314610fd957600080fd5b8063f0f2f6ee14610e8e578063f2fde38b14610ea1578063f7cb789a14610ec1578063fa0648cb14610ed7578063faddbdb214610ef757600080fd5b8063da1f57c811610108578063da1f57c814610df0578063dbab925314610e06578063dbf4025b14610e1c578063de26eadf14610e50578063ebca8add14610e7057600080fd5b8063c9fbcfb014610d64578063cb1c2b5c14610d79578063cb56532014610d95578063cb6b532e14610daf578063d20e43411461075657600080fd5b8063a6edbfa8116101d2578063af85bdbc11610196578063af85bdbc14610c9a578063b116944414610cb0578063b370488014610ce8578063c566482c14610d22578063c9f73df614610d4f57600080fd5b8063a6edbfa814610bcf578063aafbc82114610bef578063ab5669ad14610c2a578063abd3f61214610c3f578063ae1eac9114610c7a57600080fd5b806398dfca7f1161021957806398dfca7f14610b195780639cbe5efd14610b39578063a1b44ff814610b4f578063a34398a214610b6f578063a345bf4314610bba57600080fd5b80638aec8542146109be5780638c65c81f146109d35780638da5cb5b14610ab55780638f32b2fe14610ad357806390cc399c14610b1157600080fd5b806352a5f1f81161037157806368aa6ffc116102ee57806376c154a5116102b257806376c154a5146109265780637838c03114610953578063783fe32f146109685780637fc4eda81461097b5780638396c2b01461099057600080fd5b806368aa6ffc146108735780636920c820146108a05780636a842462146108ce578063715018a6146108e457806371e51e9e146108f957600080fd5b80636157714c116103355780636157714c146107cb57806361613897146107ed57806363a4390b1461081a57806364febe9614610847578063687ddf3b1461085d57600080fd5b806352a5f1f8146107365780635342c8bc1461075657806353fd66fd1461076c5780635a9249e61461078c5780635fd9491d146107ac57600080fd5b806336bcf7d6116103ff57806343a70146116103c357806343a701461461069457806347ce07cc146106aa57806349208981146106de5780634c5970601461070b5780634e71d92d1461072157600080fd5b806336bcf7d6146105ff57806336f1e6c01461061c57806339c5dec7146106315780633be83035146106515780633d1b760b1461067e57600080fd5b80632007641911610446578063200764191461054e5780632d971e6314610565578063317a98771461059257806335082933146105a757806336b19cd7146105c757600080fd5b8063053b37e61461048e5780630720da52146104b75780630bab460b146104e457806312a2f1f4146104f9578063170ad53c1461053857600080fd5b3661048957005b600080fd5b34801561049a57600080fd5b506104a460035481565b6040519081526020015b60405180910390f35b3480156104c357600080fd5b506104d76104d2366004614816565b610fef565b6040516104ae919061482f565b3480156104f057600080fd5b506104a46110de565b34801561050557600080fd5b50610519610514366004614816565b6110f9565b604080516001600160a01b0390931683526020830191909152016104ae565b34801561054457600080fd5b506104a460195481565b34801561055a57600080fd5b50610563611131565b005b34801561057157600080fd5b5061057a611156565b6040516001600160801b0390911681526020016104ae565b34801561059e57600080fd5b506105636111da565b3480156105b357600080fd5b506105636105c23660046148e2565b61131d565b3480156105d357600080fd5b506005546105e7906001600160a01b031681565b6040516001600160a01b0390911681526020016104ae565b34801561060b57600080fd5b506104a46801bc16d674ec80000081565b34801561062857600080fd5b506104a4600681565b34801561063d57600080fd5b5061056361064c3660046148e2565b6114bc565b34801561065d57600080fd5b5061067161066c3660046148fd565b61165b565b6040516104ae9190614929565b34801561068a57600080fd5b506104a460025481565b3480156106a057600080fd5b506104a460095481565b3480156106b657600080fd5b506105e77f000000000000000000000000000000000000000000000000000000000000000081565b3480156106ea57600080fd5b506104a46106f93660046148e2565b60216020526000908152604090205481565b34801561071757600080fd5b506104a460145481565b34801561072d57600080fd5b50610563611998565b34801561074257600080fd5b50610563610751366004614a07565b611cf0565b34801561076257600080fd5b506104a46103e881565b34801561077857600080fd5b50610563610787366004614a8a565b611ddc565b34801561079857600080fd5b506004546105e7906001600160a01b031681565b3480156107b857600080fd5b506104a46a027b46536c66c8e300000081565b3480156107d757600080fd5b506107e0612277565b6040516104ae9190614acc565b3480156107f957600080fd5b506104a4610808366004614afe565b60116020526000908152604090205481565b34801561082657600080fd5b506104a4610835366004614816565b60156020526000908152604090205481565b34801561085357600080fd5b506104a460135481565b34801561086957600080fd5b506104a4601c5481565b34801561087f57600080fd5b506104a461088e3660046148e2565b60226020526000908152604090205481565b3480156108ac57600080fd5b506108c06108bb366004614b1b565b6122c8565b6040516104ae929190614b3d565b3480156108da57600080fd5b506104a460075481565b3480156108f057600080fd5b5061056361242e565b34801561090557600080fd5b506104a46109143660046148e2565b601e6020526000908152604090205481565b34801561093257600080fd5b506104a46109413660046148e2565b601d6020526000908152604090205481565b34801561095f57600080fd5b506104a4606481565b610563610976366004614b9f565b612440565b34801561098757600080fd5b506104a4601981565b34801561099c57600080fd5b506109b06109ab3660046148fd565b6126d6565b6040516104ae929190614bc5565b3480156109ca57600080fd5b506104a4612800565b3480156109df57600080fd5b50610a586109ee366004614816565b600c6020526000908152604090208054600182015460028301546003840154600485015460058601546006870154600788015460089098015496979596949560ff80861696610100870482169662010000810483169663010000009091049092169491939192908c565b604080519c8d5260208d019b909b52998b019890985260ff90961660608a0152931515608089015291151560a0880152151560c087015260e0860152610100850152610120840152610140830152610160820152610180016104ae565b348015610ac157600080fd5b506000546001600160a01b03166105e7565b348015610adf57600080fd5b506104a4610aee366004614c19565b600e60209081526000938452604080852082529284528284209052825290205481565b610563612855565b348015610b2557600080fd5b50610563610b34366004614816565b612bf1565b348015610b4557600080fd5b506104a460085481565b348015610b5b57600080fd5b50610563610b6a366004614816565b612c3f565b348015610b7b57600080fd5b50610baa610b8a366004614c55565b601660209081526000928352604080842090915290825290205460ff1681565b60405190151581526020016104ae565b348015610bc657600080fd5b50610563612cc9565b348015610bdb57600080fd5b50610563610bea366004614c81565b612e1a565b348015610bfb57600080fd5b50610baa610c0a366004614cd4565b602460209081526000928352604080842090915290825290205460ff1681565b348015610c3657600080fd5b506104a4603c81565b348015610c4b57600080fd5b50610c5f610c5a3660046148e2565b6131ba565b604080519384526020840192909252908201526060016104ae565b348015610c8657600080fd5b506107e0610c95366004614c55565b6132a8565b348015610ca657600080fd5b506104a4601a5481565b348015610cbc57600080fd5b506104a4610ccb366004614c55565b600f60209081526000928352604080842090915290825290205481565b348015610cf457600080fd5b50601054610d099067ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020016104ae565b348015610d2e57600080fd5b506104a4610d3d3660046148e2565b601f6020526000908152604090205481565b348015610d5b57600080fd5b506107e061332a565b348015610d7057600080fd5b5061056361337a565b348015610d8557600080fd5b506104a467016345785d8a000081565b348015610da157600080fd5b50600b54610baa9060ff1681565b348015610dbb57600080fd5b50610baa610dca366004614cfe565b601760209081526000938452604080852082529284528284209052825290205460ff1681565b348015610dfc57600080fd5b506104a460065481565b348015610e1257600080fd5b506104a4601b5481565b348015610e2857600080fd5b506105e77f000000000000000000000000000000000000000000000000000000000000000081565b348015610e5c57600080fd5b506105e7610e6b366004614b1b565b6134cb565b348015610e7c57600080fd5b506104a469163c0fb846284fa0000081565b610563610e9c366004614d31565b613503565b348015610ead57600080fd5b50610563610ebc3660046148e2565b613638565b348015610ecd57600080fd5b506104a460125481565b348015610ee357600080fd5b506104a4610ef2366004614d4c565b613673565b348015610f0357600080fd5b506104a4610f12366004614c19565b600d60209081526000938452604080852082529284528284209052825290205481565b348015610f4157600080fd5b506104a461044c81565b348015610f5757600080fd5b50610baa610f66366004614c55565b60208080526000928352604080842090915290825290205460ff1681565b348015610f9057600080fd5b50610563610f9f3660046148e2565b6136a1565b348015610fb057600080fd5b506023546104a4565b348015610fc557600080fd5b50610563610fd43660046148fd565b613a1e565b348015610fe557600080fd5b506104a4600a5481565b61104e60405180610140016040528060008152602001600060ff16815260200160001515815260200160001515815260200160001515815260200160008152602001600081526020016000815260200160008152602001600081525090565b6000828152600c6020908152604080832060028101548552600381015460ff80821687860152610100808304821615158886015262010000830482161515606089015263010000009092041615156080870152600582015460a0870152600682015460c0870152600782015460e08701526008909101549085015293825260189052919091205461012082015290565b600060056110ea612800565b6110f49190614d9b565b905090565b6023818154811061110957600080fd5b6000918252602090912060029091020180546001909101546001600160a01b03909116915082565b611139613a71565b600b805460ff191690556010805467ffffffffffffffff19169055565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638204b67a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110f49190614daf565b6111e2613a9e565b33600090815260226020526040902054806112375760405162461bcd60e51b815260206004820152601060248201526f4e6f7468696e6720746f20636c61696d60801b60448201526064015b60405180910390fd5b336000818152602260205260408082208290555190919083908381818185875af1925050503d8060008114611288576040519150601f19603f3d011682016040523d82523d6000602084013e61128d565b606091505b50509050806112d45760405162461bcd60e51b8152602060048201526013602482015272151c985b9cd9995c881353d38819985a5b1959606a1b604482015260640161122e565b604080518381526000602082015233917f987d620f307ff6b94d58743cb7a7509f24071586a77759b77c2d4e29f75a2f9a91015b60405180910390a2505061131b60018055565b565b611325613a71565b6001600160a01b03811661136d5760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206164647265737360881b604482015260640161122e565b6005546006546001600160a01b03909116901561146b57600680546000918290556040519091906001600160a01b0384169083908381818185875af1925050503d80600081146113d9576040519150601f19603f3d011682016040523d82523d6000602084013e6113de565b606091505b50509050806114255760405162461bcd60e51b8152602060048201526013602482015272119959481d1c985b9cd9995c8819985a5b1959606a1b604482015260640161122e565b826001600160a01b03167f6dda1c050330bbf19404606d86eb8277c7a84ee0b310a5311f255750f72e71ea8360405161146091815260200190565b60405180910390a250505b600580546001600160a01b0319166001600160a01b0384811691821790925560405190918316907fb03e0c2c1a6f3df4b388eee743d2ab30b064eb703533a6808a42b292cff9a97990600090a35050565b6114c4613a71565b6001600160a01b03811661150c5760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206164647265737360881b604482015260640161122e565b6004546007546001600160a01b03909116901561160a57600780546000918290556040519091906001600160a01b0384169083908381818185875af1925050503d8060008114611578576040519150601f19603f3d011682016040523d82523d6000602084013e61157d565b606091505b50509050806115c45760405162461bcd60e51b8152602060048201526013602482015272119959481d1c985b9cd9995c8819985a5b1959606a1b604482015260640161122e565b826001600160a01b03167fe1b962d6a17421db47dc42910fbf9205832ca07f240e024fbc819c44540d8812836040516115ff91815260200190565b60405180910390a250505b600480546001600160a01b0319166001600160a01b0384811691821790925560405190918316907f6d0ea9c8b710f5c47c6869e683ae5d091320fac973498fc2b9ff84140dc9838390600090a35050565b6040805160c081018252606080825260006020830181905292820183905281018290526080810182905260a08101919091526000848152600c602052604090206003810154610100900460ff166116ea5760405162461bcd60e51b8152602060048201526013602482015272149bdd5b99081b9bdd08199a5b985b1a5e9959606a1b604482015260640161122e565b600381015460ff8082166040850181905262010000830482161515606086015263010000009092041615156080840152600882015460a084015261172f908690613ac8565b6020830181905284106117a2576040805160008082526020820190925290611799565b611786604051806080016040528060006001600160a01b031681526020016000815260200160008152602001600081525090565b8152602001906001900390816117525790505b50825250611991565b60006117ae8486614dee565b905082602001518111156117c3575060208201515b60006117cf8683614e01565b90508067ffffffffffffffff8111156117ea576117ea614dd8565b60405190808252806020026020018201604052801561184f57816020015b61183c604051806080016040528060006001600160a01b031681526020016000815260200160008152602001600081525090565b8152602001906001900390816118085790505b5084526000878152601860205260408120548190815b818110801561187357508483105b156119895760008b815260186020526040812080548390811061189857611898614e14565b60009182526020808320909101548e8352600d825260408084206001600160a01b0390921680855291835280842060038d015460ff1685529092529120549091508015611974578b8610611966576000806119068f858d60030160009054906101000a900460ff1686613b65565b915091506040518060800160405280856001600160a01b03168152602001848152602001838152602001828152508c60000151888151811061194a5761194a614e14565b6020026020010181905250868061196090614e2a565b97505050505b8561197081614e2a565b9650505b5050808061198190614e2a565b915050611865565b505050505050505b9392505050565b6119a0613a9e565b33600081815260226020526040902054906119ba90613c4b565b336000908152601d6020908152604080832054601f90925290912054821515806119e45750600082115b806119ef5750600081115b611a2e5760405162461bcd60e51b815260206004820152601060248201526f4e6f7468696e6720746f20636c61696d60801b604482015260640161122e565b600080831180611a3e5750600082115b15611b2a576000612710611a546103e886614e43565b611a5e9190614d9b565b90506000611a6c8286614e01565b9050600082118015611a7f575084601954115b15611ae457600085601954611a949190614e01565b905080611aa984670de0b6b3a7640000614e43565b611ab39190614d9b565b601a6000828254611ac49190614dee565b9250508190555082601b6000828254611add9190614dee565b9091555050505b336000908152601d60209081526040808320839055601f909152812081905560198054879290611b15908490614e01565b90915550611b2590508482614dee565b925050505b8315611bcf57336000818152602260205260408082208290555190919086908381818185875af1925050503d8060008114611b81576040519150601f19603f3d011682016040523d82523d6000602084013e611b86565b606091505b5050905080611bcd5760405162461bcd60e51b8152602060048201526013602482015272151c985b9cd9995c881353d38819985a5b1959606a1b604482015260640161122e565b505b8015611ca85760405163a9059cbb60e01b8152336004820152602481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a9059cbb906044016020604051808303816000875af1158015611c42573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c669190614e5a565b611ca85760405162461bcd60e51b8152602060048201526013602482015272151c985b9cd9995c881513d2c819985a5b1959606a1b604482015260640161122e565b604080518581526020810183905233917f987d620f307ff6b94d58743cb7a7509f24071586a77759b77c2d4e29f75a2f9a910160405180910390a25050505061131b60018055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b038116611d675760405162461bcd60e51b815260206004820152601760248201527f456e74726f70792061646472657373206e6f7420736574000000000000000000604482015260640161122e565b336001600160a01b03821614611dcb5760405162461bcd60e51b815260206004820152602360248201527f4f6e6c7920456e74726f70792063616e2063616c6c20746869732066756e637460448201526234b7b760e91b606482015260840161122e565b611dd6848484613d21565b50505050565b611de4613a9e565b602354600090815b83811015612232576000858583818110611e0857611e08614e14565b905060200201359050828110611e505760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b604482015260640161122e565b8115611ee9578585611e63600185614e01565b818110611e7257611e72614e14565b90506020020135868684818110611e8b57611e8b614e14565b9050602002013510611ee95760405162461bcd60e51b815260206004820152602160248201527f496e6469636573206d75737420626520736f727465642064657363656e64696e6044820152606760f81b606482015260840161122e565b600060238281548110611efe57611efe614e14565b60009182526020918290206040805180820190915260029092020180546001600160a01b031680835260019091015492820183905260085491935091908110611f4a575050505061222a565b6000818152600c602052604090206003810154610100900460ff16611f7357505050505061222a565b6000828152602080805260408083206001600160a01b038716845290915290205460ff1615611fbc57611fa585613e17565b86611faf81614e7c565b975050505050505061222a565b6000828152600d602090815260408083206001600160a01b03871684528252808320600385015460ff168452909152902054801561220d5760038201546000906301000000900460ff1615612070576000848152600e602090815260408083206001600160a01b03891684528252808320600387015460ff1684529091529020546004840154811180159061205d57506120568382614dee565b8460040154105b1561206a57836007015491505b50612096565b670de0b6b3a76400008360060154836120899190614e43565b6120939190614d9b565b90505b80156120a6576120a68582613f46565b6000670de0b6b3a76400008460050154846120c19190614e43565b6120cb9190614d9b565b6120d59084614dee565b6001600160a01b038716600090815260226020526040812080549293508392909190612102908490614dee565b90915550506000858152602080805260408083206001600160a01b038a16808552908352818420805460ff19166001179055888452600f835281842090845290915290205480156121c5576000868152600f602090815260408083206001600160a01b038b16845290915281205561217a818d614dee565b604080518881526020810186905290810184905260608101839052909c506001600160a01b038816903390600080516020614f3e8339815191529060800160405180910390a3612209565b6040805187815260208101859052908101839052600060608201526001600160a01b038816903390600080516020614f3e8339815191529060800160405180910390a35b5050505b61221686613e17565b8761222081614e7c565b9850505050505050505b600101611dec565b50811561226857604051339083156108fc029084906000818181858888f19350505050158015612266573d6000803e3d6000fd5b505b505061227360018055565b5050565b61227f6147f7565b6008546000908152600c6020526040908190208151610320810190925260220160198282826020028201915b8154815260200190600101908083116122ab575050505050905090565b60235460609080841061231a576040805160008082526020820190925290612312565b60408051808201909152600080825260208201528152602001906001900390816122eb5790505b509150612427565b60006123268486614dee565b9050818111156123335750805b600061233f8683614e01565b90508067ffffffffffffffff81111561235a5761235a614dd8565b60405190808252806020026020018201604052801561239f57816020015b60408051808201909152600080825260208201528152602001906001900390816123785790505b50935060005b818110156124235760236123b98289614dee565b815481106123c9576123c9614e14565b60009182526020918290206040805180820190915260029092020180546001600160a01b031682526001015491810191909152855186908390811061241057612410614e14565b60209081029190910101526001016123a5565b5050505b9250929050565b612436613a71565b61131b6000613f99565b612448613a9e565b600a5442101561246a5760405162461bcd60e51b815260040161122e90614e93565b60025461247f9067016345785d8a0000614dee565b3410156124ce5760405162461bcd60e51b815260206004820152601d60248201527f53656e6420746f74616c207374616b65202b206b656570657220666565000000604482015260640161122e565b60008163ffffffff16116125195760405162461bcd60e51b8152602060048201526012602482015271139bc8189b1bd8dadcc81cd95b1958dd195960721b604482015260640161122e565b600b5460009060ff1661252e5760085461253c565b60085461253c906001614dee565b9050600082815b60198160ff1610156125885760018083169003612568578261256481614e2a565b9350505b60018263ffffffff16901c9150808061258090614ed7565b915050612543565b50600082116125ce5760405162461bcd60e51b8152602060048201526012602482015271139bc8189b1bd8dadcc81cd95b1958dd195960721b604482015260640161122e565b6000600254346125de9190614e01565b905060006125ec8483614d9b565b905060006125fa8584614ef6565b905067016345785d8a00008210156126445760405162461bcd60e51b815260206004820152600d60248201526c4d696e2070657220626c6f636b60981b604482015260640161122e565b869350600160005b60198160ff1610156126c257600180871690036126a25781156126965761268d3382856002548861267d9190614dee565b6126879190614dee565b8b613fe9565b600091506126a2565b6126a23382868b613fe9565b60018663ffffffff16901c955080806126ba90614ed7565b91505061264c565b50505050505050506126d360018055565b50565b6000838152601860205260409020546060908084106127055760408051600081526020810190915291506127f8565b60006127118486614dee565b90508181111561271e5750805b600061272a8683614e01565b90508067ffffffffffffffff81111561274557612745614dd8565b60405190808252806020026020018201604052801561276e578160200160208202803683370190505b50935060005b818110156127f45760008881526018602052604090206127948289614dee565b815481106127a4576127a4614e14565b9060005260206000200160009054906101000a90046001600160a01b03168582815181106127d4576127d4614e14565b6001600160a01b0390921660209283029190910190910152600101612774565b5050505b935093915050565b600080601c5469163c0fb846284fa0000061281b9190614dee565b905060006128346a027b46536c66c8e300000083614d9b565b90506006811115612843575060065b6801bc16d674ec800000901c92915050565b601254600a546128659190614dee565b4210156128a05760405162461bcd60e51b8152602060048201526009602482015268546f6f206561726c7960b81b604482015260640161122e565b600b5460ff16156128e55760405162461bcd60e51b815260206004820152600f60248201526e416c726561647920726f6c6c696e6760881b604482015260640161122e565b60145460085460009081526015602052604090205410156129485760405162461bcd60e51b815260206004820152601760248201527f4e6f7420656e6f756768207061727469636970616e7473000000000000000000604482015260640161122e565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638204b67a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156129a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129cc9190614daf565b9050806001600160801b0316341015612a275760405162461bcd60e51b815260206004820152601860248201527f496e73756666696369656e7420656e74726f7079206665650000000000000000604482015260640161122e565b600b805460ff1916600117905560408051637b43155d60e01b815290516000916001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691637b43155d916001600160801b038616916004808301926020929190829003018185885af1158015612aa8573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190612acd9190614f0a565b6010805467ffffffffffffffff191667ffffffffffffffff83169081179091556008546000918252601160205260409091205590506001600160801b038216341115612bad57600033612b296001600160801b03851634614e01565b604051600081818185875af1925050503d8060008114612b65576040519150601f19603f3d011682016040523d82523d6000602084013e612b6a565b606091505b5050905080612bab5760405162461bcd60e51b815260206004820152600d60248201526c1499599d5b990819985a5b1959609a1b604482015260640161122e565b505b60085460405167ffffffffffffffff831681527fb9560bd3e25a95a3fcca6c0f21c6e8d9d07165bb54ae84dd553e21bbd94ce2629060200160405180910390a25050565b612bf9613a71565b600280549082905560408051828152602081018490527fe22b4203e51a04604258271faf98bf06a6f25e13004a7bce95940d2a2adbae8c91015b60405180910390a15050565b612c47613a71565b60008111612c8b5760405162461bcd60e51b815260206004820152601160248201527004c696d6974206d757374206265203e203607c1b604482015260640161122e565b600380549082905560408051828152602081018490527fd0497f09900611069b215093d3f3a5087f9719137e3a3fc9f716995a4be91f3b9101612c33565b612cd1613a9e565b6005546001600160a01b03163314612d175760405162461bcd60e51b81526020600482015260096024820152682737ba1030b236b4b760b91b604482015260640161122e565b60065480612d5a5760405162461bcd60e51b815260206004820152601060248201526f4e6f206665657320746f20636c61696d60801b604482015260640161122e565b60006006819055604051339083908381818185875af1925050503d8060008114612da0576040519150601f19603f3d011682016040523d82523d6000602084013e612da5565b606091505b5050905080612de85760405162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b604482015260640161122e565b60405182815233907f6dda1c050330bbf19404606d86eb8277c7a84ee0b310a5311f255750f72e71ea90602001611308565b612e22613a9e565b6000805b82811015613175576000848483818110612e4257612e42614e14565b9050602002013590506008548110612e8b5760405162461bcd60e51b815260206004820152600c60248201526b1058dd1a5d99481c9bdd5b9960a21b604482015260640161122e565b6000818152600c602052604090206003810154610100900460ff16612ee85760405162461bcd60e51b8152602060048201526013602482015272149bdd5b99081b9bdd08199a5b985b1a5e9959606a1b604482015260640161122e565b6000828152602080805260408083206001600160a01b038b16845290915290205460ff1615612f1857505061316d565b6000828152600d602090815260408083206001600160a01b038b1684528252808320600385015460ff16845290915290205480156131695760038201546000906301000000900460ff1615612fcc576000848152600e602090815260408083206001600160a01b038d1684528252808320600387015460ff16845290915290205460048401548111801590612fb95750612fb28382614dee565b8460040154105b15612fc657836007015491505b50612ff2565b670de0b6b3a7640000836006015483612fe59190614e43565b612fef9190614d9b565b90505b8015613002576130028982613f46565b6000670de0b6b3a764000084600501548461301d9190614e43565b6130279190614d9b565b6130319084614dee565b6001600160a01b038b1660009081526022602052604081208054929350839290919061305e908490614dee565b90915550506000858152602080805260408083206001600160a01b038e16808552908352818420805460ff19166001179055888452600f83528184209084529091529020548015613121576000868152600f602090815260408083206001600160a01b038f1684529091528120556130d68189614dee565b6040805188815260208101869052908101849052606081018390529098506001600160a01b038c16903390600080516020614f3e8339815191529060800160405180910390a3613165565b6040805187815260208101859052908101839052600060608201526001600160a01b038c16903390600080516020614f3e8339815191529060800160405180910390a35b5050505b5050505b600101612e26565b5080156131ab57604051339082156108fc029083906000818181858888f193505050501580156131a9573d6000803e3d6000fd5b505b506131b560018055565b505050565b6001600160a01b0381166000908152601d6020908152604080832054601f835281842054601e90935290832054601a54919391111561324b576001600160a01b0384166000908152601e6020526040812054601a546132199190614e01565b90506000670de0b6b3a76400006132308684614e43565b61323a9190614d9b565b90506132468185614dee565b935050505b600083118061325a5750600082115b1561329d5760006127106132706103e886614e43565b61327a9190614d9b565b905060006132888286614e01565b90506132948482614dee565b925050506132a1565b5060005b9193909250565b6132b06147f7565b6132b86147f7565b60005b60198160ff161015613320576000858152600d602090815260408083206001600160a01b0388168452825280832060ff85168085529252909120549083906019811061330957613309614e14565b60200201528061331881614ed7565b9150506132bb565b5090505b92915050565b6133326147f7565b6008546000908152600c6020526040908190208151610320810190925260090160198282826020028201918154815260200190600101908083116122ab575050505050905090565b613382613a9e565b6004546001600160a01b031633146133c85760405162461bcd60e51b8152602060048201526009602482015268139bdd081d985d5b1d60ba1b604482015260640161122e565b6007548061340b5760405162461bcd60e51b815260206004820152601060248201526f4e6f206665657320746f20636c61696d60801b604482015260640161122e565b60006007819055604051339083908381818185875af1925050503d8060008114613451576040519150601f19603f3d011682016040523d82523d6000602084013e613456565b606091505b50509050806134995760405162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b604482015260640161122e565b60405182815233907fe1b962d6a17421db47dc42910fbf9205832ca07f240e024fbc819c44540d881290602001611308565b601860205281600052604060002081815481106134e757600080fd5b6000918252602090912001546001600160a01b03169150829050565b61350b613a9e565b600a5442101561352d5760405162461bcd60e51b815260040161122e90614e93565b600b5460009060ff1661354257600854613550565b600854613550906001614dee565b6000818152600f602090815260408083203384529091529020549091501580156135dd576002546135899067016345785d8a0000614dee565b3410156135d85760405162461bcd60e51b815260206004820152601760248201527f53656e64207374616b65202b206b656570657220666565000000000000000000604482015260640161122e565b613621565b67016345785d8a00003410156136215760405162461bcd60e51b81526020600482015260096024820152684d696e207374616b6560b81b604482015260640161122e565b61362d33843485613fe9565b50506126d360018055565b613640613a71565b6001600160a01b03811661366a57604051631e4fbdf760e01b81526000600482015260240161122e565b6126d381613f99565b6000828152600c6020526040812060090160ff83166019811061369857613698614e14565b01549392505050565b6136a9613a9e565b6001600160a01b0381166000908152602160205260408120546136cd906001614dee565b600854600354919250906136e18383614e01565b11156136f7576003546136f49083614dee565b90505b6000825b828110156139b1576000818152600c602052604090206003810154610100900460ff16158061374a57506000828152602080805260408083206001600160a01b038a16845290915290205460ff165b1561375557506139a9565b6000828152600d602090815260408083206001600160a01b038a1684528252808320600385015460ff16845290915290205480156139a65760038201546000906301000000900460ff1615613809576000848152600e602090815260408083206001600160a01b038c1684528252808320600387015460ff168452909152902054600484015481118015906137f657506137ef8382614dee565b8460040154105b1561380357836007015491505b5061382f565b670de0b6b3a76400008360060154836138229190614e43565b61382c9190614d9b565b90505b801561383f5761383f8882613f46565b6000670de0b6b3a764000084600501548461385a9190614e43565b6138649190614d9b565b61386e9084614dee565b6001600160a01b038a1660009081526022602052604081208054929350839290919061389b908490614dee565b90915550506000858152602080805260408083206001600160a01b038d16808552908352818420805460ff19166001179055888452600f8352818420908452909152902054801561395e576000868152600f602090815260408083206001600160a01b038e1684529091528120556139138188614dee565b6040805188815260208101869052908101849052606081018390529097506001600160a01b038b16903390600080516020614f3e8339815191529060800160405180910390a36139a2565b6040805187815260208101859052908101839052600060608201526001600160a01b038b16903390600080516020614f3e8339815191529060800160405180910390a35b5050505b50505b6001016136fb565b5081156139dd576139c3600183614e01565b6001600160a01b0385166000908152602160205260409020555b8015613a1257604051339082156108fc029083906000818181858888f19350505050158015613a10573d6000803e3d6000fd5b505b5050506126d360018055565b613a26613a71565b603c831015613a635760405162461bcd60e51b8152602060048201526009602482015268151bdbc81cda1bdc9d60ba1b604482015260640161122e565b601292909255601455601355565b6000546001600160a01b0316331461131b5760405163118cdaa760e01b815233600482015260240161122e565b600260015403613ac157604051633ee5aeb560e01b815260040160405180910390fd5b6002600155565b600082815260186020526040812054815b81811015613b5d576000858152600d6020908152604080832060189092528220805483919085908110613b0e57613b0e614e14565b60009182526020808320909101546001600160a01b03168352828101939093526040918201812060ff891682529092529020541115613b555782613b5181614e2a565b9350505b600101613ad9565b505092915050565b6000848152600c602052604081206005810154829190670de0b6b3a764000090613b8f9086614e43565b613b999190614d9b565b613ba39085614dee565b60038201549093506301000000900460ff1615613c1b576000878152600e602090815260408083206001600160a01b038a168452825280832060ff8916845290915290205460048201548111801590613c085750613c018582614dee565b8260040154105b15613c1557816007015492505b50613c41565b670de0b6b3a7640000816006015485613c349190614e43565b613c3e9190614d9b565b91505b5094509492505050565b6001600160a01b0381166000908152601e6020526040902054601a541115613d02576001600160a01b0381166000908152601e6020526040812054601a54613c939190614e01565b6001600160a01b0383166000908152601d6020526040812054919250670de0b6b3a7640000613cc28385614e43565b613ccc9190614d9b565b6001600160a01b0385166000908152601f6020526040812080549293508392909190613cf9908490614dee565b90915550505050505b601a546001600160a01b039091166000908152601e6020526040902055565b67ffffffffffffffff8316600090815260116020526040902054600b5460ff168015613d4e575060085481145b613d8d5760405162461bcd60e51b815260206004820152601060248201526f496e76616c69642073657175656e636560801b604482015260640161122e565b60405182908190600090613db1908390600190602001918252602082015260400190565b60408051601f19818403018152828252805160209182012081840187905260028484015282518085038401815260609094019092528251920191909120909150613dfc8383836140a2565b50506010805467ffffffffffffffff19169055505050505050565b602354600090613e2990600190614e01565b9050600060238381548110613e4057613e40614e14565b60009182526020808320604080518082018252600290940290910180546001600160a01b03168085526001909101548484019081529085526024835281852090518552909152909120805460ff191690559050828214613f075760238281548110613ead57613ead614e14565b906000526020600020906002020160238481548110613ece57613ece614e14565b60009182526020909120825460029092020180546001600160a01b0319166001600160a01b039092169190911781556001918201549101555b6023805480613f1857613f18614f27565b60008281526020812060026000199093019283020180546001600160a01b0319168155600101559055505050565b613f4f82613c4b565b6001600160a01b0382166000908152601d602052604081208054839290613f77908490614dee565b925050819055508060196000828254613f909190614dee565b90915550505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60198360ff161061402c5760405162461bcd60e51b815260206004820152600d60248201526c496e76616c696420426c6f636b60981b604482015260640161122e565b6000818152600f602090815260408083206001600160a01b0388168452909152902054829015801561408e576002546140659085614e01565b6002546000858152600f602090815260408083206001600160a01b038c16845290915290205591505b61409a8686848661444f565b505050505050565b6008546000908152600c602052604090206140be601985614ef6565b60038201805460ff191660ff929092169190911790556140e4610271602086901c614ef6565b60038201805462ff000019811692156201000002928317909155600091600984019160ff9081169116176019811061411e5761411e614e14565b0154600183018190556002830154909150600061413b8383614e01565b808555905060008390036141b1576000612710614159606485614e43565b6141639190614d9b565b905080600660008282546141779190614dee565b9091555061418790508184614e01565b600760008282546141989190614dee565b9091555050600060058601819055600686015550614363565b60006127106141c1606484614e43565b6141cb9190614d9b565b905060006127106141de6103e885614e43565b6141e89190614d9b565b905060006141f68284614dee565b9050826006600082825461420a9190614dee565b9250508190555081600760008282546142239190614dee565b90915550600090506142358286614e01565b90508661424a82670de0b6b3a7640000614e43565b6142549190614d9b565b60058901556000614263612800565b9050600061426f6110de565b60038b015490915062010000900460ff1661429c5780600960008282546142969190614dee565b90915550505b60038a015460009062010000900460ff16156142cc57826009546142c09190614dee565b600060095590506142cf565b50815b80601c60008282546142e19190614dee565b909155506142f2905060028e614ef6565b6000036143295760038b01805463ff0000001916630100000017905560078b0181905561431f8a8d614ef6565b60048c015561435b565b60038b01805463ff000000191690558961434b82670de0b6b3a7640000614e43565b6143559190614d9b565b60068c01555b505050505050505b60038401805461010061ff00198216179182905542600880880191909155546040805191825260ff92831660208301526301000000840483161515908201526201000090920416151560608201527f73b6989256872bd8853751760a7960291ec2e04e1d8191bd624381f27fca9f8e9060800160405180910390a1600880549060006143ee83614e2a565b90915550506013546144009042614dee565b600a819055600b805460ff19169055600854604051918252907f278844837bcf8364a705384bf3a2812901f54155bae86dea81dd52aa5b9ec0e39060200160405180910390a250505050505050565b6000818152600c6020526040812060090160ff85166019811061447457614474614e14565b01546000838152600d602090815260408083206001600160a01b038a168452825280832060ff89168452909152812054919250036144dd576000828152600e602090815260408083206001600160a01b0389168452825280832060ff8816845290915290208190555b6000828152600d602090815260408083206001600160a01b0389168452825280832060ff881684529091528120805485929061451a908490614dee565b90915550506000828152600c60205260409020839060090160ff86166019811061454657614546614e14565b0160008282546145569190614dee565b90915550506000828152600c60205260408120600201805485929061457c908490614dee565b9091555050600082815260176020908152604080832060ff80891685529083528184206001600160a01b038a168552909252909120541661462557600082815260176020908152604080832060ff88168085529083528184206001600160a01b038a1685528352818420805460ff19166001179055858452600c909252909120602201906019811061461057614610614e14565b01805490600061461f83614e2a565b91905055505b60008281526016602090815260408083206001600160a01b038916845290915290205460ff166147a25760008281526016602090815260408083206001600160a01b03891684528252808320805460ff191660011790558483526015909152812080549161469283614e2a565b9091555050600082815260186020908152604080832080546001810182559084528284200180546001600160a01b0319166001600160a01b038a1690811790915583526024825280832085845290915290205460ff166147a2576001600160a01b03858116600081815260246020908152604080832087845282528083208054600160ff1990911681179091558151808301909252938152908101868152602380549485018155909252517fd57b2b5166478fd4318d2acc6cc2c704584312bdd8781b32d5d06abda57f4230600290930292830180546001600160a01b031916919094161790925590517fd57b2b5166478fd4318d2acc6cc2c704584312bdd8781b32d5d06abda57f4231909101555b6040805183815260ff861660208201529081018490526001600160a01b038616907f60c16227b368ec1b75014bc56837d084cbaf0b6989beb0cced9d343d9b5a94679060600160405180910390a25050505050565b6040518061032001604052806019906020820280368337509192915050565b60006020828403121561482857600080fd5b5035919050565b8151815260208083015161014083019161484d9084018260ff169052565b506040830151614861604084018215159052565b506060830151614875606084018215159052565b506080830151614889608084018215159052565b5060a083015160a083015260c083015160c083015260e083015160e083015261010083015161010083015261012083015161012083015292915050565b80356001600160a01b03811681146148dd57600080fd5b919050565b6000602082840312156148f457600080fd5b611991826148c6565b60008060006060848603121561491257600080fd5b505081359360208301359350604090920135919050565b6020808252825160c083830152805160e08401819052600092919091019082906101008501905b8083101561499c57835160018060a01b03815116835260208101516020840152604081015160408401526060810151606084015250608082019150602084019350600183019250614950565b5060208601516040860152604086015192506149bd606086018460ff169052565b606086015180151560808701529250608086015180151560a0870152925060a086015160c086015280935050505092915050565b67ffffffffffffffff811681146126d357600080fd5b600080600060608486031215614a1c57600080fd5b8335614a27816149f1565b9250614a35602085016148c6565b9150604084013590509250925092565b60008083601f840112614a5757600080fd5b50813567ffffffffffffffff811115614a6f57600080fd5b6020830191508360208260051b850101111561242757600080fd5b60008060208385031215614a9d57600080fd5b823567ffffffffffffffff811115614ab457600080fd5b614ac085828601614a45565b90969095509350505050565b6103208101818360005b6019811015614af5578151835260209283019290910190600101614ad6565b50505092915050565b600060208284031215614b1057600080fd5b8135611991816149f1565b60008060408385031215614b2e57600080fd5b50508035926020909101359150565b6040808252835190820181905260009060208501906060840190835b81811015614b8c57835180516001600160a01b031684526020908101518185015290930192604090920191600101614b59565b5050602093909301939093525092915050565b600060208284031215614bb157600080fd5b813563ffffffff8116811461199157600080fd5b6040808252835190820181905260009060208501906060840190835b81811015614b8c5783516001600160a01b0316835260209384019390920191600101614be1565b803560ff811681146148dd57600080fd5b600080600060608486031215614c2e57600080fd5b83359250614c3e602085016148c6565b9150614c4c60408501614c08565b90509250925092565b60008060408385031215614c6857600080fd5b82359150614c78602084016148c6565b90509250929050565b600080600060408486031215614c9657600080fd5b614c9f846148c6565b9250602084013567ffffffffffffffff811115614cbb57600080fd5b614cc786828701614a45565b9497909650939450505050565b60008060408385031215614ce757600080fd5b614cf0836148c6565b946020939093013593505050565b600080600060608486031215614d1357600080fd5b83359250614d2360208501614c08565b9150614c4c604085016148c6565b600060208284031215614d4357600080fd5b61199182614c08565b60008060408385031215614d5f57600080fd5b82359150614c7860208401614c08565b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600082614daa57614daa614d6f565b500490565b600060208284031215614dc157600080fd5b81516001600160801b038116811461199157600080fd5b634e487b7160e01b600052604160045260246000fd5b8082018082111561332457613324614d85565b8181038181111561332457613324614d85565b634e487b7160e01b600052603260045260246000fd5b600060018201614e3c57614e3c614d85565b5060010190565b808202811582820484141761332457613324614d85565b600060208284031215614e6c57600080fd5b8151801515811461199157600080fd5b600081614e8b57614e8b614d85565b506000190190565b60208082526024908201527f526f756e64206e6f742073746172746564207965742028696e7465726d697373604082015263696f6e2960e01b606082015260800190565b600060ff821660ff8103614eed57614eed614d85565b60010192915050565b600082614f0557614f05614d6f565b500690565b600060208284031215614f1c57600080fd5b8151611991816149f1565b634e487b7160e01b600052603160045260246000fdfe07f32f6f4c1b7fe2a67cebec7f6546a6324a14e661023fa65d8dd4e6605183a2a264697066735822122084fd1ca0ad41a672fa65085d0cb27f203b2f08017c9fac58f993355b2f5e4d7764736f6c634300081c0033000000000000000000000000d458261e832415cfd3bae5e416fdf3230ce6f1340000000000000000000000000b4de26631b54b0aa272d0e9b1e46fb723db4a1100000000000000000000000099662e7cc1970de202e97d5b2b70215d5370b1f400000000000000000000000099662e7cc1970de202e97d5b2b70215d5370b1f4

Deployed Bytecode

0x6080604052600436106104825760003560e01c80638aec854211610255578063c9fbcfb011610144578063f0f2f6ee116100c1578063fbb098ee11610085578063fbb098ee14610f35578063fc44e4c714610f4b578063fc89aeaa14610f84578063fcfd837f14610fa4578063fd5c0cc614610fb9578063fe31a61314610fd957600080fd5b8063f0f2f6ee14610e8e578063f2fde38b14610ea1578063f7cb789a14610ec1578063fa0648cb14610ed7578063faddbdb214610ef757600080fd5b8063da1f57c811610108578063da1f57c814610df0578063dbab925314610e06578063dbf4025b14610e1c578063de26eadf14610e50578063ebca8add14610e7057600080fd5b8063c9fbcfb014610d64578063cb1c2b5c14610d79578063cb56532014610d95578063cb6b532e14610daf578063d20e43411461075657600080fd5b8063a6edbfa8116101d2578063af85bdbc11610196578063af85bdbc14610c9a578063b116944414610cb0578063b370488014610ce8578063c566482c14610d22578063c9f73df614610d4f57600080fd5b8063a6edbfa814610bcf578063aafbc82114610bef578063ab5669ad14610c2a578063abd3f61214610c3f578063ae1eac9114610c7a57600080fd5b806398dfca7f1161021957806398dfca7f14610b195780639cbe5efd14610b39578063a1b44ff814610b4f578063a34398a214610b6f578063a345bf4314610bba57600080fd5b80638aec8542146109be5780638c65c81f146109d35780638da5cb5b14610ab55780638f32b2fe14610ad357806390cc399c14610b1157600080fd5b806352a5f1f81161037157806368aa6ffc116102ee57806376c154a5116102b257806376c154a5146109265780637838c03114610953578063783fe32f146109685780637fc4eda81461097b5780638396c2b01461099057600080fd5b806368aa6ffc146108735780636920c820146108a05780636a842462146108ce578063715018a6146108e457806371e51e9e146108f957600080fd5b80636157714c116103355780636157714c146107cb57806361613897146107ed57806363a4390b1461081a57806364febe9614610847578063687ddf3b1461085d57600080fd5b806352a5f1f8146107365780635342c8bc1461075657806353fd66fd1461076c5780635a9249e61461078c5780635fd9491d146107ac57600080fd5b806336bcf7d6116103ff57806343a70146116103c357806343a701461461069457806347ce07cc146106aa57806349208981146106de5780634c5970601461070b5780634e71d92d1461072157600080fd5b806336bcf7d6146105ff57806336f1e6c01461061c57806339c5dec7146106315780633be83035146106515780633d1b760b1461067e57600080fd5b80632007641911610446578063200764191461054e5780632d971e6314610565578063317a98771461059257806335082933146105a757806336b19cd7146105c757600080fd5b8063053b37e61461048e5780630720da52146104b75780630bab460b146104e457806312a2f1f4146104f9578063170ad53c1461053857600080fd5b3661048957005b600080fd5b34801561049a57600080fd5b506104a460035481565b6040519081526020015b60405180910390f35b3480156104c357600080fd5b506104d76104d2366004614816565b610fef565b6040516104ae919061482f565b3480156104f057600080fd5b506104a46110de565b34801561050557600080fd5b50610519610514366004614816565b6110f9565b604080516001600160a01b0390931683526020830191909152016104ae565b34801561054457600080fd5b506104a460195481565b34801561055a57600080fd5b50610563611131565b005b34801561057157600080fd5b5061057a611156565b6040516001600160801b0390911681526020016104ae565b34801561059e57600080fd5b506105636111da565b3480156105b357600080fd5b506105636105c23660046148e2565b61131d565b3480156105d357600080fd5b506005546105e7906001600160a01b031681565b6040516001600160a01b0390911681526020016104ae565b34801561060b57600080fd5b506104a46801bc16d674ec80000081565b34801561062857600080fd5b506104a4600681565b34801561063d57600080fd5b5061056361064c3660046148e2565b6114bc565b34801561065d57600080fd5b5061067161066c3660046148fd565b61165b565b6040516104ae9190614929565b34801561068a57600080fd5b506104a460025481565b3480156106a057600080fd5b506104a460095481565b3480156106b657600080fd5b506105e77f000000000000000000000000d458261e832415cfd3bae5e416fdf3230ce6f13481565b3480156106ea57600080fd5b506104a46106f93660046148e2565b60216020526000908152604090205481565b34801561071757600080fd5b506104a460145481565b34801561072d57600080fd5b50610563611998565b34801561074257600080fd5b50610563610751366004614a07565b611cf0565b34801561076257600080fd5b506104a46103e881565b34801561077857600080fd5b50610563610787366004614a8a565b611ddc565b34801561079857600080fd5b506004546105e7906001600160a01b031681565b3480156107b857600080fd5b506104a46a027b46536c66c8e300000081565b3480156107d757600080fd5b506107e0612277565b6040516104ae9190614acc565b3480156107f957600080fd5b506104a4610808366004614afe565b60116020526000908152604090205481565b34801561082657600080fd5b506104a4610835366004614816565b60156020526000908152604090205481565b34801561085357600080fd5b506104a460135481565b34801561086957600080fd5b506104a4601c5481565b34801561087f57600080fd5b506104a461088e3660046148e2565b60226020526000908152604090205481565b3480156108ac57600080fd5b506108c06108bb366004614b1b565b6122c8565b6040516104ae929190614b3d565b3480156108da57600080fd5b506104a460075481565b3480156108f057600080fd5b5061056361242e565b34801561090557600080fd5b506104a46109143660046148e2565b601e6020526000908152604090205481565b34801561093257600080fd5b506104a46109413660046148e2565b601d6020526000908152604090205481565b34801561095f57600080fd5b506104a4606481565b610563610976366004614b9f565b612440565b34801561098757600080fd5b506104a4601981565b34801561099c57600080fd5b506109b06109ab3660046148fd565b6126d6565b6040516104ae929190614bc5565b3480156109ca57600080fd5b506104a4612800565b3480156109df57600080fd5b50610a586109ee366004614816565b600c6020526000908152604090208054600182015460028301546003840154600485015460058601546006870154600788015460089098015496979596949560ff80861696610100870482169662010000810483169663010000009091049092169491939192908c565b604080519c8d5260208d019b909b52998b019890985260ff90961660608a0152931515608089015291151560a0880152151560c087015260e0860152610100850152610120840152610140830152610160820152610180016104ae565b348015610ac157600080fd5b506000546001600160a01b03166105e7565b348015610adf57600080fd5b506104a4610aee366004614c19565b600e60209081526000938452604080852082529284528284209052825290205481565b610563612855565b348015610b2557600080fd5b50610563610b34366004614816565b612bf1565b348015610b4557600080fd5b506104a460085481565b348015610b5b57600080fd5b50610563610b6a366004614816565b612c3f565b348015610b7b57600080fd5b50610baa610b8a366004614c55565b601660209081526000928352604080842090915290825290205460ff1681565b60405190151581526020016104ae565b348015610bc657600080fd5b50610563612cc9565b348015610bdb57600080fd5b50610563610bea366004614c81565b612e1a565b348015610bfb57600080fd5b50610baa610c0a366004614cd4565b602460209081526000928352604080842090915290825290205460ff1681565b348015610c3657600080fd5b506104a4603c81565b348015610c4b57600080fd5b50610c5f610c5a3660046148e2565b6131ba565b604080519384526020840192909252908201526060016104ae565b348015610c8657600080fd5b506107e0610c95366004614c55565b6132a8565b348015610ca657600080fd5b506104a4601a5481565b348015610cbc57600080fd5b506104a4610ccb366004614c55565b600f60209081526000928352604080842090915290825290205481565b348015610cf457600080fd5b50601054610d099067ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020016104ae565b348015610d2e57600080fd5b506104a4610d3d3660046148e2565b601f6020526000908152604090205481565b348015610d5b57600080fd5b506107e061332a565b348015610d7057600080fd5b5061056361337a565b348015610d8557600080fd5b506104a467016345785d8a000081565b348015610da157600080fd5b50600b54610baa9060ff1681565b348015610dbb57600080fd5b50610baa610dca366004614cfe565b601760209081526000938452604080852082529284528284209052825290205460ff1681565b348015610dfc57600080fd5b506104a460065481565b348015610e1257600080fd5b506104a4601b5481565b348015610e2857600080fd5b506105e77f0000000000000000000000000b4de26631b54b0aa272d0e9b1e46fb723db4a1181565b348015610e5c57600080fd5b506105e7610e6b366004614b1b565b6134cb565b348015610e7c57600080fd5b506104a469163c0fb846284fa0000081565b610563610e9c366004614d31565b613503565b348015610ead57600080fd5b50610563610ebc3660046148e2565b613638565b348015610ecd57600080fd5b506104a460125481565b348015610ee357600080fd5b506104a4610ef2366004614d4c565b613673565b348015610f0357600080fd5b506104a4610f12366004614c19565b600d60209081526000938452604080852082529284528284209052825290205481565b348015610f4157600080fd5b506104a461044c81565b348015610f5757600080fd5b50610baa610f66366004614c55565b60208080526000928352604080842090915290825290205460ff1681565b348015610f9057600080fd5b50610563610f9f3660046148e2565b6136a1565b348015610fb057600080fd5b506023546104a4565b348015610fc557600080fd5b50610563610fd43660046148fd565b613a1e565b348015610fe557600080fd5b506104a4600a5481565b61104e60405180610140016040528060008152602001600060ff16815260200160001515815260200160001515815260200160001515815260200160008152602001600081526020016000815260200160008152602001600081525090565b6000828152600c6020908152604080832060028101548552600381015460ff80821687860152610100808304821615158886015262010000830482161515606089015263010000009092041615156080870152600582015460a0870152600682015460c0870152600782015460e08701526008909101549085015293825260189052919091205461012082015290565b600060056110ea612800565b6110f49190614d9b565b905090565b6023818154811061110957600080fd5b6000918252602090912060029091020180546001909101546001600160a01b03909116915082565b611139613a71565b600b805460ff191690556010805467ffffffffffffffff19169055565b60007f000000000000000000000000d458261e832415cfd3bae5e416fdf3230ce6f1346001600160a01b0316638204b67a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110f49190614daf565b6111e2613a9e565b33600090815260226020526040902054806112375760405162461bcd60e51b815260206004820152601060248201526f4e6f7468696e6720746f20636c61696d60801b60448201526064015b60405180910390fd5b336000818152602260205260408082208290555190919083908381818185875af1925050503d8060008114611288576040519150601f19603f3d011682016040523d82523d6000602084013e61128d565b606091505b50509050806112d45760405162461bcd60e51b8152602060048201526013602482015272151c985b9cd9995c881353d38819985a5b1959606a1b604482015260640161122e565b604080518381526000602082015233917f987d620f307ff6b94d58743cb7a7509f24071586a77759b77c2d4e29f75a2f9a91015b60405180910390a2505061131b60018055565b565b611325613a71565b6001600160a01b03811661136d5760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206164647265737360881b604482015260640161122e565b6005546006546001600160a01b03909116901561146b57600680546000918290556040519091906001600160a01b0384169083908381818185875af1925050503d80600081146113d9576040519150601f19603f3d011682016040523d82523d6000602084013e6113de565b606091505b50509050806114255760405162461bcd60e51b8152602060048201526013602482015272119959481d1c985b9cd9995c8819985a5b1959606a1b604482015260640161122e565b826001600160a01b03167f6dda1c050330bbf19404606d86eb8277c7a84ee0b310a5311f255750f72e71ea8360405161146091815260200190565b60405180910390a250505b600580546001600160a01b0319166001600160a01b0384811691821790925560405190918316907fb03e0c2c1a6f3df4b388eee743d2ab30b064eb703533a6808a42b292cff9a97990600090a35050565b6114c4613a71565b6001600160a01b03811661150c5760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206164647265737360881b604482015260640161122e565b6004546007546001600160a01b03909116901561160a57600780546000918290556040519091906001600160a01b0384169083908381818185875af1925050503d8060008114611578576040519150601f19603f3d011682016040523d82523d6000602084013e61157d565b606091505b50509050806115c45760405162461bcd60e51b8152602060048201526013602482015272119959481d1c985b9cd9995c8819985a5b1959606a1b604482015260640161122e565b826001600160a01b03167fe1b962d6a17421db47dc42910fbf9205832ca07f240e024fbc819c44540d8812836040516115ff91815260200190565b60405180910390a250505b600480546001600160a01b0319166001600160a01b0384811691821790925560405190918316907f6d0ea9c8b710f5c47c6869e683ae5d091320fac973498fc2b9ff84140dc9838390600090a35050565b6040805160c081018252606080825260006020830181905292820183905281018290526080810182905260a08101919091526000848152600c602052604090206003810154610100900460ff166116ea5760405162461bcd60e51b8152602060048201526013602482015272149bdd5b99081b9bdd08199a5b985b1a5e9959606a1b604482015260640161122e565b600381015460ff8082166040850181905262010000830482161515606086015263010000009092041615156080840152600882015460a084015261172f908690613ac8565b6020830181905284106117a2576040805160008082526020820190925290611799565b611786604051806080016040528060006001600160a01b031681526020016000815260200160008152602001600081525090565b8152602001906001900390816117525790505b50825250611991565b60006117ae8486614dee565b905082602001518111156117c3575060208201515b60006117cf8683614e01565b90508067ffffffffffffffff8111156117ea576117ea614dd8565b60405190808252806020026020018201604052801561184f57816020015b61183c604051806080016040528060006001600160a01b031681526020016000815260200160008152602001600081525090565b8152602001906001900390816118085790505b5084526000878152601860205260408120548190815b818110801561187357508483105b156119895760008b815260186020526040812080548390811061189857611898614e14565b60009182526020808320909101548e8352600d825260408084206001600160a01b0390921680855291835280842060038d015460ff1685529092529120549091508015611974578b8610611966576000806119068f858d60030160009054906101000a900460ff1686613b65565b915091506040518060800160405280856001600160a01b03168152602001848152602001838152602001828152508c60000151888151811061194a5761194a614e14565b6020026020010181905250868061196090614e2a565b97505050505b8561197081614e2a565b9650505b5050808061198190614e2a565b915050611865565b505050505050505b9392505050565b6119a0613a9e565b33600081815260226020526040902054906119ba90613c4b565b336000908152601d6020908152604080832054601f90925290912054821515806119e45750600082115b806119ef5750600081115b611a2e5760405162461bcd60e51b815260206004820152601060248201526f4e6f7468696e6720746f20636c61696d60801b604482015260640161122e565b600080831180611a3e5750600082115b15611b2a576000612710611a546103e886614e43565b611a5e9190614d9b565b90506000611a6c8286614e01565b9050600082118015611a7f575084601954115b15611ae457600085601954611a949190614e01565b905080611aa984670de0b6b3a7640000614e43565b611ab39190614d9b565b601a6000828254611ac49190614dee565b9250508190555082601b6000828254611add9190614dee565b9091555050505b336000908152601d60209081526040808320839055601f909152812081905560198054879290611b15908490614e01565b90915550611b2590508482614dee565b925050505b8315611bcf57336000818152602260205260408082208290555190919086908381818185875af1925050503d8060008114611b81576040519150601f19603f3d011682016040523d82523d6000602084013e611b86565b606091505b5050905080611bcd5760405162461bcd60e51b8152602060048201526013602482015272151c985b9cd9995c881353d38819985a5b1959606a1b604482015260640161122e565b505b8015611ca85760405163a9059cbb60e01b8152336004820152602481018290527f0000000000000000000000000b4de26631b54b0aa272d0e9b1e46fb723db4a116001600160a01b03169063a9059cbb906044016020604051808303816000875af1158015611c42573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c669190614e5a565b611ca85760405162461bcd60e51b8152602060048201526013602482015272151c985b9cd9995c881513d2c819985a5b1959606a1b604482015260640161122e565b604080518581526020810183905233917f987d620f307ff6b94d58743cb7a7509f24071586a77759b77c2d4e29f75a2f9a910160405180910390a25050505061131b60018055565b7f000000000000000000000000d458261e832415cfd3bae5e416fdf3230ce6f1346001600160a01b038116611d675760405162461bcd60e51b815260206004820152601760248201527f456e74726f70792061646472657373206e6f7420736574000000000000000000604482015260640161122e565b336001600160a01b03821614611dcb5760405162461bcd60e51b815260206004820152602360248201527f4f6e6c7920456e74726f70792063616e2063616c6c20746869732066756e637460448201526234b7b760e91b606482015260840161122e565b611dd6848484613d21565b50505050565b611de4613a9e565b602354600090815b83811015612232576000858583818110611e0857611e08614e14565b905060200201359050828110611e505760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b604482015260640161122e565b8115611ee9578585611e63600185614e01565b818110611e7257611e72614e14565b90506020020135868684818110611e8b57611e8b614e14565b9050602002013510611ee95760405162461bcd60e51b815260206004820152602160248201527f496e6469636573206d75737420626520736f727465642064657363656e64696e6044820152606760f81b606482015260840161122e565b600060238281548110611efe57611efe614e14565b60009182526020918290206040805180820190915260029092020180546001600160a01b031680835260019091015492820183905260085491935091908110611f4a575050505061222a565b6000818152600c602052604090206003810154610100900460ff16611f7357505050505061222a565b6000828152602080805260408083206001600160a01b038716845290915290205460ff1615611fbc57611fa585613e17565b86611faf81614e7c565b975050505050505061222a565b6000828152600d602090815260408083206001600160a01b03871684528252808320600385015460ff168452909152902054801561220d5760038201546000906301000000900460ff1615612070576000848152600e602090815260408083206001600160a01b03891684528252808320600387015460ff1684529091529020546004840154811180159061205d57506120568382614dee565b8460040154105b1561206a57836007015491505b50612096565b670de0b6b3a76400008360060154836120899190614e43565b6120939190614d9b565b90505b80156120a6576120a68582613f46565b6000670de0b6b3a76400008460050154846120c19190614e43565b6120cb9190614d9b565b6120d59084614dee565b6001600160a01b038716600090815260226020526040812080549293508392909190612102908490614dee565b90915550506000858152602080805260408083206001600160a01b038a16808552908352818420805460ff19166001179055888452600f835281842090845290915290205480156121c5576000868152600f602090815260408083206001600160a01b038b16845290915281205561217a818d614dee565b604080518881526020810186905290810184905260608101839052909c506001600160a01b038816903390600080516020614f3e8339815191529060800160405180910390a3612209565b6040805187815260208101859052908101839052600060608201526001600160a01b038816903390600080516020614f3e8339815191529060800160405180910390a35b5050505b61221686613e17565b8761222081614e7c565b9850505050505050505b600101611dec565b50811561226857604051339083156108fc029084906000818181858888f19350505050158015612266573d6000803e3d6000fd5b505b505061227360018055565b5050565b61227f6147f7565b6008546000908152600c6020526040908190208151610320810190925260220160198282826020028201915b8154815260200190600101908083116122ab575050505050905090565b60235460609080841061231a576040805160008082526020820190925290612312565b60408051808201909152600080825260208201528152602001906001900390816122eb5790505b509150612427565b60006123268486614dee565b9050818111156123335750805b600061233f8683614e01565b90508067ffffffffffffffff81111561235a5761235a614dd8565b60405190808252806020026020018201604052801561239f57816020015b60408051808201909152600080825260208201528152602001906001900390816123785790505b50935060005b818110156124235760236123b98289614dee565b815481106123c9576123c9614e14565b60009182526020918290206040805180820190915260029092020180546001600160a01b031682526001015491810191909152855186908390811061241057612410614e14565b60209081029190910101526001016123a5565b5050505b9250929050565b612436613a71565b61131b6000613f99565b612448613a9e565b600a5442101561246a5760405162461bcd60e51b815260040161122e90614e93565b60025461247f9067016345785d8a0000614dee565b3410156124ce5760405162461bcd60e51b815260206004820152601d60248201527f53656e6420746f74616c207374616b65202b206b656570657220666565000000604482015260640161122e565b60008163ffffffff16116125195760405162461bcd60e51b8152602060048201526012602482015271139bc8189b1bd8dadcc81cd95b1958dd195960721b604482015260640161122e565b600b5460009060ff1661252e5760085461253c565b60085461253c906001614dee565b9050600082815b60198160ff1610156125885760018083169003612568578261256481614e2a565b9350505b60018263ffffffff16901c9150808061258090614ed7565b915050612543565b50600082116125ce5760405162461bcd60e51b8152602060048201526012602482015271139bc8189b1bd8dadcc81cd95b1958dd195960721b604482015260640161122e565b6000600254346125de9190614e01565b905060006125ec8483614d9b565b905060006125fa8584614ef6565b905067016345785d8a00008210156126445760405162461bcd60e51b815260206004820152600d60248201526c4d696e2070657220626c6f636b60981b604482015260640161122e565b869350600160005b60198160ff1610156126c257600180871690036126a25781156126965761268d3382856002548861267d9190614dee565b6126879190614dee565b8b613fe9565b600091506126a2565b6126a23382868b613fe9565b60018663ffffffff16901c955080806126ba90614ed7565b91505061264c565b50505050505050506126d360018055565b50565b6000838152601860205260409020546060908084106127055760408051600081526020810190915291506127f8565b60006127118486614dee565b90508181111561271e5750805b600061272a8683614e01565b90508067ffffffffffffffff81111561274557612745614dd8565b60405190808252806020026020018201604052801561276e578160200160208202803683370190505b50935060005b818110156127f45760008881526018602052604090206127948289614dee565b815481106127a4576127a4614e14565b9060005260206000200160009054906101000a90046001600160a01b03168582815181106127d4576127d4614e14565b6001600160a01b0390921660209283029190910190910152600101612774565b5050505b935093915050565b600080601c5469163c0fb846284fa0000061281b9190614dee565b905060006128346a027b46536c66c8e300000083614d9b565b90506006811115612843575060065b6801bc16d674ec800000901c92915050565b601254600a546128659190614dee565b4210156128a05760405162461bcd60e51b8152602060048201526009602482015268546f6f206561726c7960b81b604482015260640161122e565b600b5460ff16156128e55760405162461bcd60e51b815260206004820152600f60248201526e416c726561647920726f6c6c696e6760881b604482015260640161122e565b60145460085460009081526015602052604090205410156129485760405162461bcd60e51b815260206004820152601760248201527f4e6f7420656e6f756768207061727469636970616e7473000000000000000000604482015260640161122e565b60007f000000000000000000000000d458261e832415cfd3bae5e416fdf3230ce6f1346001600160a01b0316638204b67a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156129a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129cc9190614daf565b9050806001600160801b0316341015612a275760405162461bcd60e51b815260206004820152601860248201527f496e73756666696369656e7420656e74726f7079206665650000000000000000604482015260640161122e565b600b805460ff1916600117905560408051637b43155d60e01b815290516000916001600160a01b037f000000000000000000000000d458261e832415cfd3bae5e416fdf3230ce6f1341691637b43155d916001600160801b038616916004808301926020929190829003018185885af1158015612aa8573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190612acd9190614f0a565b6010805467ffffffffffffffff191667ffffffffffffffff83169081179091556008546000918252601160205260409091205590506001600160801b038216341115612bad57600033612b296001600160801b03851634614e01565b604051600081818185875af1925050503d8060008114612b65576040519150601f19603f3d011682016040523d82523d6000602084013e612b6a565b606091505b5050905080612bab5760405162461bcd60e51b815260206004820152600d60248201526c1499599d5b990819985a5b1959609a1b604482015260640161122e565b505b60085460405167ffffffffffffffff831681527fb9560bd3e25a95a3fcca6c0f21c6e8d9d07165bb54ae84dd553e21bbd94ce2629060200160405180910390a25050565b612bf9613a71565b600280549082905560408051828152602081018490527fe22b4203e51a04604258271faf98bf06a6f25e13004a7bce95940d2a2adbae8c91015b60405180910390a15050565b612c47613a71565b60008111612c8b5760405162461bcd60e51b815260206004820152601160248201527004c696d6974206d757374206265203e203607c1b604482015260640161122e565b600380549082905560408051828152602081018490527fd0497f09900611069b215093d3f3a5087f9719137e3a3fc9f716995a4be91f3b9101612c33565b612cd1613a9e565b6005546001600160a01b03163314612d175760405162461bcd60e51b81526020600482015260096024820152682737ba1030b236b4b760b91b604482015260640161122e565b60065480612d5a5760405162461bcd60e51b815260206004820152601060248201526f4e6f206665657320746f20636c61696d60801b604482015260640161122e565b60006006819055604051339083908381818185875af1925050503d8060008114612da0576040519150601f19603f3d011682016040523d82523d6000602084013e612da5565b606091505b5050905080612de85760405162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b604482015260640161122e565b60405182815233907f6dda1c050330bbf19404606d86eb8277c7a84ee0b310a5311f255750f72e71ea90602001611308565b612e22613a9e565b6000805b82811015613175576000848483818110612e4257612e42614e14565b9050602002013590506008548110612e8b5760405162461bcd60e51b815260206004820152600c60248201526b1058dd1a5d99481c9bdd5b9960a21b604482015260640161122e565b6000818152600c602052604090206003810154610100900460ff16612ee85760405162461bcd60e51b8152602060048201526013602482015272149bdd5b99081b9bdd08199a5b985b1a5e9959606a1b604482015260640161122e565b6000828152602080805260408083206001600160a01b038b16845290915290205460ff1615612f1857505061316d565b6000828152600d602090815260408083206001600160a01b038b1684528252808320600385015460ff16845290915290205480156131695760038201546000906301000000900460ff1615612fcc576000848152600e602090815260408083206001600160a01b038d1684528252808320600387015460ff16845290915290205460048401548111801590612fb95750612fb28382614dee565b8460040154105b15612fc657836007015491505b50612ff2565b670de0b6b3a7640000836006015483612fe59190614e43565b612fef9190614d9b565b90505b8015613002576130028982613f46565b6000670de0b6b3a764000084600501548461301d9190614e43565b6130279190614d9b565b6130319084614dee565b6001600160a01b038b1660009081526022602052604081208054929350839290919061305e908490614dee565b90915550506000858152602080805260408083206001600160a01b038e16808552908352818420805460ff19166001179055888452600f83528184209084529091529020548015613121576000868152600f602090815260408083206001600160a01b038f1684529091528120556130d68189614dee565b6040805188815260208101869052908101849052606081018390529098506001600160a01b038c16903390600080516020614f3e8339815191529060800160405180910390a3613165565b6040805187815260208101859052908101839052600060608201526001600160a01b038c16903390600080516020614f3e8339815191529060800160405180910390a35b5050505b5050505b600101612e26565b5080156131ab57604051339082156108fc029083906000818181858888f193505050501580156131a9573d6000803e3d6000fd5b505b506131b560018055565b505050565b6001600160a01b0381166000908152601d6020908152604080832054601f835281842054601e90935290832054601a54919391111561324b576001600160a01b0384166000908152601e6020526040812054601a546132199190614e01565b90506000670de0b6b3a76400006132308684614e43565b61323a9190614d9b565b90506132468185614dee565b935050505b600083118061325a5750600082115b1561329d5760006127106132706103e886614e43565b61327a9190614d9b565b905060006132888286614e01565b90506132948482614dee565b925050506132a1565b5060005b9193909250565b6132b06147f7565b6132b86147f7565b60005b60198160ff161015613320576000858152600d602090815260408083206001600160a01b0388168452825280832060ff85168085529252909120549083906019811061330957613309614e14565b60200201528061331881614ed7565b9150506132bb565b5090505b92915050565b6133326147f7565b6008546000908152600c6020526040908190208151610320810190925260090160198282826020028201918154815260200190600101908083116122ab575050505050905090565b613382613a9e565b6004546001600160a01b031633146133c85760405162461bcd60e51b8152602060048201526009602482015268139bdd081d985d5b1d60ba1b604482015260640161122e565b6007548061340b5760405162461bcd60e51b815260206004820152601060248201526f4e6f206665657320746f20636c61696d60801b604482015260640161122e565b60006007819055604051339083908381818185875af1925050503d8060008114613451576040519150601f19603f3d011682016040523d82523d6000602084013e613456565b606091505b50509050806134995760405162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b604482015260640161122e565b60405182815233907fe1b962d6a17421db47dc42910fbf9205832ca07f240e024fbc819c44540d881290602001611308565b601860205281600052604060002081815481106134e757600080fd5b6000918252602090912001546001600160a01b03169150829050565b61350b613a9e565b600a5442101561352d5760405162461bcd60e51b815260040161122e90614e93565b600b5460009060ff1661354257600854613550565b600854613550906001614dee565b6000818152600f602090815260408083203384529091529020549091501580156135dd576002546135899067016345785d8a0000614dee565b3410156135d85760405162461bcd60e51b815260206004820152601760248201527f53656e64207374616b65202b206b656570657220666565000000000000000000604482015260640161122e565b613621565b67016345785d8a00003410156136215760405162461bcd60e51b81526020600482015260096024820152684d696e207374616b6560b81b604482015260640161122e565b61362d33843485613fe9565b50506126d360018055565b613640613a71565b6001600160a01b03811661366a57604051631e4fbdf760e01b81526000600482015260240161122e565b6126d381613f99565b6000828152600c6020526040812060090160ff83166019811061369857613698614e14565b01549392505050565b6136a9613a9e565b6001600160a01b0381166000908152602160205260408120546136cd906001614dee565b600854600354919250906136e18383614e01565b11156136f7576003546136f49083614dee565b90505b6000825b828110156139b1576000818152600c602052604090206003810154610100900460ff16158061374a57506000828152602080805260408083206001600160a01b038a16845290915290205460ff165b1561375557506139a9565b6000828152600d602090815260408083206001600160a01b038a1684528252808320600385015460ff16845290915290205480156139a65760038201546000906301000000900460ff1615613809576000848152600e602090815260408083206001600160a01b038c1684528252808320600387015460ff168452909152902054600484015481118015906137f657506137ef8382614dee565b8460040154105b1561380357836007015491505b5061382f565b670de0b6b3a76400008360060154836138229190614e43565b61382c9190614d9b565b90505b801561383f5761383f8882613f46565b6000670de0b6b3a764000084600501548461385a9190614e43565b6138649190614d9b565b61386e9084614dee565b6001600160a01b038a1660009081526022602052604081208054929350839290919061389b908490614dee565b90915550506000858152602080805260408083206001600160a01b038d16808552908352818420805460ff19166001179055888452600f8352818420908452909152902054801561395e576000868152600f602090815260408083206001600160a01b038e1684529091528120556139138188614dee565b6040805188815260208101869052908101849052606081018390529097506001600160a01b038b16903390600080516020614f3e8339815191529060800160405180910390a36139a2565b6040805187815260208101859052908101839052600060608201526001600160a01b038b16903390600080516020614f3e8339815191529060800160405180910390a35b5050505b50505b6001016136fb565b5081156139dd576139c3600183614e01565b6001600160a01b0385166000908152602160205260409020555b8015613a1257604051339082156108fc029083906000818181858888f19350505050158015613a10573d6000803e3d6000fd5b505b5050506126d360018055565b613a26613a71565b603c831015613a635760405162461bcd60e51b8152602060048201526009602482015268151bdbc81cda1bdc9d60ba1b604482015260640161122e565b601292909255601455601355565b6000546001600160a01b0316331461131b5760405163118cdaa760e01b815233600482015260240161122e565b600260015403613ac157604051633ee5aeb560e01b815260040160405180910390fd5b6002600155565b600082815260186020526040812054815b81811015613b5d576000858152600d6020908152604080832060189092528220805483919085908110613b0e57613b0e614e14565b60009182526020808320909101546001600160a01b03168352828101939093526040918201812060ff891682529092529020541115613b555782613b5181614e2a565b9350505b600101613ad9565b505092915050565b6000848152600c602052604081206005810154829190670de0b6b3a764000090613b8f9086614e43565b613b999190614d9b565b613ba39085614dee565b60038201549093506301000000900460ff1615613c1b576000878152600e602090815260408083206001600160a01b038a168452825280832060ff8916845290915290205460048201548111801590613c085750613c018582614dee565b8260040154105b15613c1557816007015492505b50613c41565b670de0b6b3a7640000816006015485613c349190614e43565b613c3e9190614d9b565b91505b5094509492505050565b6001600160a01b0381166000908152601e6020526040902054601a541115613d02576001600160a01b0381166000908152601e6020526040812054601a54613c939190614e01565b6001600160a01b0383166000908152601d6020526040812054919250670de0b6b3a7640000613cc28385614e43565b613ccc9190614d9b565b6001600160a01b0385166000908152601f6020526040812080549293508392909190613cf9908490614dee565b90915550505050505b601a546001600160a01b039091166000908152601e6020526040902055565b67ffffffffffffffff8316600090815260116020526040902054600b5460ff168015613d4e575060085481145b613d8d5760405162461bcd60e51b815260206004820152601060248201526f496e76616c69642073657175656e636560801b604482015260640161122e565b60405182908190600090613db1908390600190602001918252602082015260400190565b60408051601f19818403018152828252805160209182012081840187905260028484015282518085038401815260609094019092528251920191909120909150613dfc8383836140a2565b50506010805467ffffffffffffffff19169055505050505050565b602354600090613e2990600190614e01565b9050600060238381548110613e4057613e40614e14565b60009182526020808320604080518082018252600290940290910180546001600160a01b03168085526001909101548484019081529085526024835281852090518552909152909120805460ff191690559050828214613f075760238281548110613ead57613ead614e14565b906000526020600020906002020160238481548110613ece57613ece614e14565b60009182526020909120825460029092020180546001600160a01b0319166001600160a01b039092169190911781556001918201549101555b6023805480613f1857613f18614f27565b60008281526020812060026000199093019283020180546001600160a01b0319168155600101559055505050565b613f4f82613c4b565b6001600160a01b0382166000908152601d602052604081208054839290613f77908490614dee565b925050819055508060196000828254613f909190614dee565b90915550505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60198360ff161061402c5760405162461bcd60e51b815260206004820152600d60248201526c496e76616c696420426c6f636b60981b604482015260640161122e565b6000818152600f602090815260408083206001600160a01b0388168452909152902054829015801561408e576002546140659085614e01565b6002546000858152600f602090815260408083206001600160a01b038c16845290915290205591505b61409a8686848661444f565b505050505050565b6008546000908152600c602052604090206140be601985614ef6565b60038201805460ff191660ff929092169190911790556140e4610271602086901c614ef6565b60038201805462ff000019811692156201000002928317909155600091600984019160ff9081169116176019811061411e5761411e614e14565b0154600183018190556002830154909150600061413b8383614e01565b808555905060008390036141b1576000612710614159606485614e43565b6141639190614d9b565b905080600660008282546141779190614dee565b9091555061418790508184614e01565b600760008282546141989190614dee565b9091555050600060058601819055600686015550614363565b60006127106141c1606484614e43565b6141cb9190614d9b565b905060006127106141de6103e885614e43565b6141e89190614d9b565b905060006141f68284614dee565b9050826006600082825461420a9190614dee565b9250508190555081600760008282546142239190614dee565b90915550600090506142358286614e01565b90508661424a82670de0b6b3a7640000614e43565b6142549190614d9b565b60058901556000614263612800565b9050600061426f6110de565b60038b015490915062010000900460ff1661429c5780600960008282546142969190614dee565b90915550505b60038a015460009062010000900460ff16156142cc57826009546142c09190614dee565b600060095590506142cf565b50815b80601c60008282546142e19190614dee565b909155506142f2905060028e614ef6565b6000036143295760038b01805463ff0000001916630100000017905560078b0181905561431f8a8d614ef6565b60048c015561435b565b60038b01805463ff000000191690558961434b82670de0b6b3a7640000614e43565b6143559190614d9b565b60068c01555b505050505050505b60038401805461010061ff00198216179182905542600880880191909155546040805191825260ff92831660208301526301000000840483161515908201526201000090920416151560608201527f73b6989256872bd8853751760a7960291ec2e04e1d8191bd624381f27fca9f8e9060800160405180910390a1600880549060006143ee83614e2a565b90915550506013546144009042614dee565b600a819055600b805460ff19169055600854604051918252907f278844837bcf8364a705384bf3a2812901f54155bae86dea81dd52aa5b9ec0e39060200160405180910390a250505050505050565b6000818152600c6020526040812060090160ff85166019811061447457614474614e14565b01546000838152600d602090815260408083206001600160a01b038a168452825280832060ff89168452909152812054919250036144dd576000828152600e602090815260408083206001600160a01b0389168452825280832060ff8816845290915290208190555b6000828152600d602090815260408083206001600160a01b0389168452825280832060ff881684529091528120805485929061451a908490614dee565b90915550506000828152600c60205260409020839060090160ff86166019811061454657614546614e14565b0160008282546145569190614dee565b90915550506000828152600c60205260408120600201805485929061457c908490614dee565b9091555050600082815260176020908152604080832060ff80891685529083528184206001600160a01b038a168552909252909120541661462557600082815260176020908152604080832060ff88168085529083528184206001600160a01b038a1685528352818420805460ff19166001179055858452600c909252909120602201906019811061461057614610614e14565b01805490600061461f83614e2a565b91905055505b60008281526016602090815260408083206001600160a01b038916845290915290205460ff166147a25760008281526016602090815260408083206001600160a01b03891684528252808320805460ff191660011790558483526015909152812080549161469283614e2a565b9091555050600082815260186020908152604080832080546001810182559084528284200180546001600160a01b0319166001600160a01b038a1690811790915583526024825280832085845290915290205460ff166147a2576001600160a01b03858116600081815260246020908152604080832087845282528083208054600160ff1990911681179091558151808301909252938152908101868152602380549485018155909252517fd57b2b5166478fd4318d2acc6cc2c704584312bdd8781b32d5d06abda57f4230600290930292830180546001600160a01b031916919094161790925590517fd57b2b5166478fd4318d2acc6cc2c704584312bdd8781b32d5d06abda57f4231909101555b6040805183815260ff861660208201529081018490526001600160a01b038616907f60c16227b368ec1b75014bc56837d084cbaf0b6989beb0cced9d343d9b5a94679060600160405180910390a25050505050565b6040518061032001604052806019906020820280368337509192915050565b60006020828403121561482857600080fd5b5035919050565b8151815260208083015161014083019161484d9084018260ff169052565b506040830151614861604084018215159052565b506060830151614875606084018215159052565b506080830151614889608084018215159052565b5060a083015160a083015260c083015160c083015260e083015160e083015261010083015161010083015261012083015161012083015292915050565b80356001600160a01b03811681146148dd57600080fd5b919050565b6000602082840312156148f457600080fd5b611991826148c6565b60008060006060848603121561491257600080fd5b505081359360208301359350604090920135919050565b6020808252825160c083830152805160e08401819052600092919091019082906101008501905b8083101561499c57835160018060a01b03815116835260208101516020840152604081015160408401526060810151606084015250608082019150602084019350600183019250614950565b5060208601516040860152604086015192506149bd606086018460ff169052565b606086015180151560808701529250608086015180151560a0870152925060a086015160c086015280935050505092915050565b67ffffffffffffffff811681146126d357600080fd5b600080600060608486031215614a1c57600080fd5b8335614a27816149f1565b9250614a35602085016148c6565b9150604084013590509250925092565b60008083601f840112614a5757600080fd5b50813567ffffffffffffffff811115614a6f57600080fd5b6020830191508360208260051b850101111561242757600080fd5b60008060208385031215614a9d57600080fd5b823567ffffffffffffffff811115614ab457600080fd5b614ac085828601614a45565b90969095509350505050565b6103208101818360005b6019811015614af5578151835260209283019290910190600101614ad6565b50505092915050565b600060208284031215614b1057600080fd5b8135611991816149f1565b60008060408385031215614b2e57600080fd5b50508035926020909101359150565b6040808252835190820181905260009060208501906060840190835b81811015614b8c57835180516001600160a01b031684526020908101518185015290930192604090920191600101614b59565b5050602093909301939093525092915050565b600060208284031215614bb157600080fd5b813563ffffffff8116811461199157600080fd5b6040808252835190820181905260009060208501906060840190835b81811015614b8c5783516001600160a01b0316835260209384019390920191600101614be1565b803560ff811681146148dd57600080fd5b600080600060608486031215614c2e57600080fd5b83359250614c3e602085016148c6565b9150614c4c60408501614c08565b90509250925092565b60008060408385031215614c6857600080fd5b82359150614c78602084016148c6565b90509250929050565b600080600060408486031215614c9657600080fd5b614c9f846148c6565b9250602084013567ffffffffffffffff811115614cbb57600080fd5b614cc786828701614a45565b9497909650939450505050565b60008060408385031215614ce757600080fd5b614cf0836148c6565b946020939093013593505050565b600080600060608486031215614d1357600080fd5b83359250614d2360208501614c08565b9150614c4c604085016148c6565b600060208284031215614d4357600080fd5b61199182614c08565b60008060408385031215614d5f57600080fd5b82359150614c7860208401614c08565b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600082614daa57614daa614d6f565b500490565b600060208284031215614dc157600080fd5b81516001600160801b038116811461199157600080fd5b634e487b7160e01b600052604160045260246000fd5b8082018082111561332457613324614d85565b8181038181111561332457613324614d85565b634e487b7160e01b600052603260045260246000fd5b600060018201614e3c57614e3c614d85565b5060010190565b808202811582820484141761332457613324614d85565b600060208284031215614e6c57600080fd5b8151801515811461199157600080fd5b600081614e8b57614e8b614d85565b506000190190565b60208082526024908201527f526f756e64206e6f742073746172746564207965742028696e7465726d697373604082015263696f6e2960e01b606082015260800190565b600060ff821660ff8103614eed57614eed614d85565b60010192915050565b600082614f0557614f05614d6f565b500690565b600060208284031215614f1c57600080fd5b8151611991816149f1565b634e487b7160e01b600052603160045260246000fdfe07f32f6f4c1b7fe2a67cebec7f6546a6324a14e661023fa65d8dd4e6605183a2a264697066735822122084fd1ca0ad41a672fa65085d0cb27f203b2f08017c9fac58f993355b2f5e4d7764736f6c634300081c0033

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

000000000000000000000000d458261e832415cfd3bae5e416fdf3230ce6f1340000000000000000000000000b4de26631b54b0aa272d0e9b1e46fb723db4a1100000000000000000000000099662e7cc1970de202e97d5b2b70215d5370b1f400000000000000000000000099662e7cc1970de202e97d5b2b70215d5370b1f4

-----Decoded View---------------
Arg [0] : _entropy (address): 0xD458261E832415CFd3BAE5E416FdF3230ce6F134
Arg [1] : _token (address): 0x0b4DE26631B54b0AA272D0e9b1e46fB723dB4a11
Arg [2] : _protocolVault (address): 0x99662E7CC1970DE202e97D5B2b70215D5370B1f4
Arg [3] : _adminWallet (address): 0x99662E7CC1970DE202e97D5B2b70215D5370B1f4

-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000d458261e832415cfd3bae5e416fdf3230ce6f134
Arg [1] : 0000000000000000000000000b4de26631b54b0aa272d0e9b1e46fb723db4a11
Arg [2] : 00000000000000000000000099662e7cc1970de202e97d5b2b70215d5370b1f4
Arg [3] : 00000000000000000000000099662e7cc1970de202e97d5b2b70215d5370b1f4


Block Transaction Gas Used Reward
view all blocks produced

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

Validator Index Block Amount
View All Withdrawals

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

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