ETH Price: $3,347.81 (-1.37%)

Contract

0x00000000009f22B55D3105e5CfF7D1a6503cF3cE
 

Overview

ETH Balance

1.48752 ETH

Eth Value

$4,979.94 (@ $3,347.81/ETH)

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Refund196089582024-04-08 5:46:23228 days ago1712555183IN
0x00000000...6503cF3cE
0 ETH0.001078199.31353091
Claim Prizes191661102024-02-06 2:05:11291 days ago1707185111IN
0x00000000...6503cF3cE
0 ETH0.0016364920.18918522
Claim Prizes190595732024-01-22 3:20:59306 days ago1705893659IN
0x00000000...6503cF3cE
0 ETH0.000842613.17689467
Enter190385562024-01-19 4:35:23309 days ago1705638923IN
0x00000000...6503cF3cE
0 ETH0.0028165823.03408928
Claim Prizes190335272024-01-18 11:43:35309 days ago1705578215IN
0x00000000...6503cF3cE
0 ETH0.0018250228.54001867
Enter190332432024-01-18 10:46:23309 days ago1705574783IN
0x00000000...6503cF3cE
0.03 ETH0.000927229.05417458
Enter190332402024-01-18 10:45:47309 days ago1705574747IN
0x00000000...6503cF3cE
0.03 ETH0.0009293829.12248425
Enter190332382024-01-18 10:45:23309 days ago1705574723IN
0x00000000...6503cF3cE
0.03 ETH0.0009839930.83382098
Claim Prizes190308842024-01-18 2:51:23310 days ago1705546283IN
0x00000000...6503cF3cE
0 ETH0.0017302127.05747614
Claim Prizes190305242024-01-18 1:38:47310 days ago1705541927IN
0x00000000...6503cF3cE
0 ETH0.0027894332.59832499
Claim Prizes190303682024-01-18 1:07:35310 days ago1705540055IN
0x00000000...6503cF3cE
0 ETH0.0022953135.89451423
Reveal190303662024-01-18 1:07:11310 days ago1705540031IN
0x00000000...6503cF3cE
0 ETH0.0056191938.04775451
Enter190303542024-01-18 1:04:47310 days ago1705539887IN
0x00000000...6503cF3cE
0 ETH0.0067036135.43457594
Enter190283662024-01-17 18:24:23310 days ago1705515863IN
0x00000000...6503cF3cE
0 ETH0.0042760235.93211606
Enter190152932024-01-15 22:33:47312 days ago1705358027IN
0x00000000...6503cF3cE
0 ETH0.0021611621.20808244
Claim Prizes190148192024-01-15 20:58:11312 days ago1705352291IN
0x00000000...6503cF3cE
0 ETH0.0012544419.61730617
Enter190144792024-01-15 19:50:11312 days ago1705348211IN
0x00000000...6503cF3cE
0 ETH0.0028023927.500654
Claim Prizes190143992024-01-15 19:34:11312 days ago1705347251IN
0x00000000...6503cF3cE
0 ETH0.002273230.41000403
Reveal190143512024-01-15 19:24:35312 days ago1705346675IN
0x00000000...6503cF3cE
0 ETH0.0047275631.913013
Enter190143442024-01-15 19:23:11312 days ago1705346591IN
0x00000000...6503cF3cE
0 ETH0.0061084532.28858683
Enter190143242024-01-15 19:19:11312 days ago1705346351IN
0x00000000...6503cF3cE
0 ETH0.00348634.20905737
Enter190131442024-01-15 15:21:59312 days ago1705332119IN
0x00000000...6503cF3cE
0 ETH0.0027606227.09074115
Claim Prizes190125202024-01-15 13:16:23312 days ago1705324583IN
0x00000000...6503cF3cE
0 ETH0.0019667530.75654595
Claim Prizes190099642024-01-15 4:41:47313 days ago1705293707IN
0x00000000...6503cF3cE
0 ETH0.0011023917.24263622
Reveal190099392024-01-15 4:36:47313 days ago1705293407IN
0x00000000...6503cF3cE
0 ETH0.0027631618.65252467
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To
189789822024-01-10 20:37:35317 days ago1704919055
0x00000000...6503cF3cE
0.0000195 ETH
189774862024-01-10 15:36:59317 days ago1704901019
0x00000000...6503cF3cE
1 ETH
189729642024-01-10 0:25:23318 days ago1704846323
0x00000000...6503cF3cE
1 ETH
189627012024-01-08 13:51:23319 days ago1704721883
0x00000000...6503cF3cE
0.25 ETH
187896142023-12-15 6:04:59343 days ago1702620299
0x00000000...6503cF3cE
1.19 ETH
187723072023-12-12 19:52:47346 days ago1702410767
0x00000000...6503cF3cE
2 ETH
187608052023-12-11 5:13:47347 days ago1702271627
0x00000000...6503cF3cE
1.19 ETH
187525772023-12-10 1:36:47349 days ago1702172207
0x00000000...6503cF3cE
0.2975 ETH
187525742023-12-10 1:36:11349 days ago1702172171
0x00000000...6503cF3cE
0.2975 ETH
187525692023-12-10 1:35:11349 days ago1702172111
0x00000000...6503cF3cE
0.2975 ETH
187495572023-12-09 15:26:59349 days ago1702135619
0x00000000...6503cF3cE
0.2975 ETH
187492862023-12-09 14:32:11349 days ago1702132331
0x00000000...6503cF3cE
0.595 ETH
187492072023-12-09 14:16:11349 days ago1702131371
0x00000000...6503cF3cE
0.0125 ETH
187427332023-12-08 16:28:23350 days ago1702052903
0x00000000...6503cF3cE
0.19 ETH
187427302023-12-08 16:27:47350 days ago1702052867
0x00000000...6503cF3cE
1.19 ETH
187427232023-12-08 16:26:23350 days ago1702052783
0x00000000...6503cF3cE
0.05 ETH
187414542023-12-08 12:10:59350 days ago1702037459
0x00000000...6503cF3cE
0.2975 ETH
187401582023-12-08 7:49:59350 days ago1702021799
0x00000000...6503cF3cE
0.2975 ETH
187397572023-12-08 6:29:11350 days ago1702016951
0x00000000...6503cF3cE
0.2975 ETH
187397522023-12-08 6:28:11350 days ago1702016891
0x00000000...6503cF3cE
0.2975 ETH
187397482023-12-08 6:27:23350 days ago1702016843
0x00000000...6503cF3cE
0.0125 ETH
187310342023-12-07 1:06:47352 days ago1701911207
0x00000000...6503cF3cE
2.95 ETH
187281052023-12-06 15:14:11352 days ago1701875651
0x00000000...6503cF3cE
2.95 ETH
187278442023-12-06 14:20:11352 days ago1701872411
0x00000000...6503cF3cE
0.1 ETH
187109402023-12-04 5:32:47354 days ago1701667967
0x00000000...6503cF3cE
0.2975 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
PokeTheBear

Compiler Version
v0.8.20+commit.a1b79de6

Optimization Enabled:
Yes with 888888 runs

Other Settings:
london EvmVersion
File 1 of 20 : PokeTheBear.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

import {LowLevelWETH} from "@looksrare/contracts-libs/contracts/lowLevelCallers/LowLevelWETH.sol";
import {LowLevelERC20Transfer} from "@looksrare/contracts-libs/contracts/lowLevelCallers/LowLevelERC20Transfer.sol";
import {PackableReentrancyGuard} from "@looksrare/contracts-libs/contracts/PackableReentrancyGuard.sol";
import {Pausable} from "@looksrare/contracts-libs/contracts/Pausable.sol";

import {ITransferManager} from "@looksrare/contracts-transfer-manager/contracts/interfaces/ITransferManager.sol";

import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
import {VRFCoordinatorV2Interface} from "@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol";
import {VRFConsumerBaseV2} from "@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol";

import {IPokeTheBear} from "./interfaces/IPokeTheBear.sol";

//       ∩___∩
//      |ノ      ヽ
//     /   ●    ● | クマ──!!
//    |     (_●_) ミ
//   彡、     |∪|  、`\
// / __    ヽノ /´>   )
// (___)     /  (_/
//   |        /
//   |   /\  \
//   | /     )   )
//    ∪     (   \
//            \_)

/**
 * @title Poke The Bear, a bear might maul you to death if you poke it.
 * @author LooksRare protocol team (👀,💎)
 */
contract PokeTheBear is
    IPokeTheBear,
    AccessControl,
    Pausable,
    PackableReentrancyGuard,
    LowLevelERC20Transfer,
    LowLevelWETH,
    VRFConsumerBaseV2
{
    /**
     * @notice Operators are allowed to commit rounds
     */
    bytes32 private constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE");

    /**
     * @notice 100% in basis points.
     */
    uint256 private constant ONE_HUNDRED_PERCENT_IN_BASIS_POINTS = 10_000;

    /**
     * @notice The maximum number of players per round.
     */
    uint256 private constant MAXIMUM_NUMBER_OF_PLAYERS_PER_ROUND = 32;

    /**
     * @notice The minimum duration for a round.
     */
    uint40 private constant MINIMUM_ROUND_DURATION = 1 minutes;

    /**
     * @notice The maximum duration for a round.
     */
    uint40 private constant MAXIMUM_ROUND_DURATION = 1 hours;

    /**
     * @notice Wrapped native token address. (WETH for most chains)
     */
    address private immutable WRAPPED_NATIVE_TOKEN;

    /**
     * @notice The key hash of the Chainlink VRF.
     */
    bytes32 private immutable KEY_HASH;

    /**
     * @notice The subscription ID of the Chainlink VRF.
     */
    uint64 private immutable SUBSCRIPTION_ID;

    /**
     * @notice The Chainlink VRF coordinator.
     */
    VRFCoordinatorV2Interface private immutable VRF_COORDINATOR;

    /**
     * @notice The transfer manager to handle ERC-20 deposits.
     */
    ITransferManager private immutable TRANSFER_MANAGER;

    mapping(uint256 requestId => RandomnessRequest) public randomnessRequests;

    mapping(uint256 caveId => mapping(uint256 => Round)) private rounds;

    /**
     * @notice Player participations in each round.
     * @dev 65,536 x 256 = 16,777,216 rounds, which is enough for 5 minutes rounds for 159 years.
     */
    mapping(address playerAddress => mapping(uint256 caveId => uint256[65536] roundIds)) private playerParticipations;

    mapping(uint256 caveId => Cave) public caves;

    /**
     * @notice The address of the protocol fee recipient.
     */
    address public protocolFeeRecipient;

    /**
     * @notice The next cave ID.
     */
    uint256 public nextCaveId = 1;

    /**
     * @param _owner The owner of the contract.
     * @param _protocolFeeRecipient The address of the protocol fee recipient.
     * @param wrappedNativeToken The wrapped native token address.
     * @param _transferManager The transfer manager to handle ERC-20 deposits.
     * @param keyHash The key hash of the Chainlink VRF.
     * @param vrfCoordinator The Chainlink VRF coordinator.
     * @param subscriptionId The subscription ID of the Chainlink VRF.
     */
    constructor(
        address _owner,
        address _operator,
        address _protocolFeeRecipient,
        address wrappedNativeToken,
        address _transferManager,
        bytes32 keyHash,
        address vrfCoordinator,
        uint64 subscriptionId
    ) VRFConsumerBaseV2(vrfCoordinator) {
        _grantRole(DEFAULT_ADMIN_ROLE, _owner);
        _grantRole(OPERATOR_ROLE, _operator);
        WRAPPED_NATIVE_TOKEN = wrappedNativeToken;
        KEY_HASH = keyHash;
        VRF_COORDINATOR = VRFCoordinatorV2Interface(vrfCoordinator);
        SUBSCRIPTION_ID = subscriptionId;
        TRANSFER_MANAGER = ITransferManager(_transferManager);

        _updateProtocolFeeRecipient(_protocolFeeRecipient);
    }

    /**
     * @inheritdoc IPokeTheBear
     */
    function addCave(
        uint256 enterAmount,
        address enterCurrency,
        uint8 playersPerRound,
        uint40 roundDuration,
        uint16 protocolFeeBp
    ) external returns (uint256 caveId) {
        _validateIsOwner();

        if (playersPerRound < 2) {
            revert InsufficientNumberOfPlayers();
        }

        if (playersPerRound > MAXIMUM_NUMBER_OF_PLAYERS_PER_ROUND) {
            revert ExceedsMaximumNumberOfPlayersPerRound();
        }

        if (protocolFeeBp > 2_500) {
            revert ProtocolFeeBasisPointsTooHigh();
        }

        unchecked {
            if (
                (enterAmount - ((enterAmount * protocolFeeBp) / ONE_HUNDRED_PERCENT_IN_BASIS_POINTS)) %
                    (playersPerRound - 1) !=
                0
            ) {
                revert IndivisibleEnterAmount();
            }
        }

        if (roundDuration < MINIMUM_ROUND_DURATION || roundDuration > MAXIMUM_ROUND_DURATION) {
            revert InvalidRoundDuration();
        }

        caveId = nextCaveId;

        caves[caveId].enterAmount = enterAmount;
        caves[caveId].enterCurrency = enterCurrency;
        caves[caveId].playersPerRound = playersPerRound;
        caves[caveId].roundDuration = roundDuration;
        caves[caveId].protocolFeeBp = protocolFeeBp;
        caves[caveId].isActive = true;

        _open({caveId: caveId, roundId: 1});

        unchecked {
            ++nextCaveId;
        }

        emit CaveAdded(caveId, enterAmount, enterCurrency, roundDuration, playersPerRound, protocolFeeBp);
    }

    /**
     * @inheritdoc IPokeTheBear
     */
    function removeCave(uint256 caveId) external {
        _validateIsOwner();

        Cave storage cave = caves[caveId];
        if (cave.roundsCount < cave.lastCommittedRoundId) {
            revert RoundsIncomplete();
        }

        caves[caveId].isActive = false;
        emit CaveRemoved(caveId);
    }

    /**
     * @inheritdoc IPokeTheBear
     */
    function commit(CommitmentCalldata[] calldata commitments) external {
        _validateIsOperator();
        uint256 commitmentsLength = commitments.length;
        for (uint256 i; i < commitmentsLength; ) {
            uint256 caveId = commitments[i].caveId;
            Cave storage cave = caves[caveId];
            if (!cave.isActive) {
                revert InactiveCave();
            }

            uint256 startingRoundId = cave.lastCommittedRoundId + 1;

            bytes32[] calldata perCaveCommitments = commitments[i].commitments;
            uint256 perCaveCommitmentsLength = perCaveCommitments.length;

            for (uint256 j; j < perCaveCommitmentsLength; ) {
                uint256 roundId = startingRoundId + j;
                bytes32 commitment = perCaveCommitments[j];

                if (commitment == bytes32(0)) {
                    revert InvalidCommitment(caveId, roundId);
                }

                rounds[caveId][roundId].commitment = commitment;

                unchecked {
                    ++j;
                }
            }

            cave.lastCommittedRoundId = uint40(startingRoundId + perCaveCommitmentsLength - 1);

            unchecked {
                ++i;
            }
        }

        emit CommitmentsSubmitted(commitments);
    }

    /**
     * @inheritdoc IPokeTheBear
     */
    function updateProtocolFeeRecipient(address _protocolFeeRecipient) external {
        _validateIsOwner();
        _updateProtocolFeeRecipient(_protocolFeeRecipient);
    }

    /**
     * @inheritdoc IPokeTheBear
     * @notice As rounds to enter are in numerical order and cannot be skipped,
               entering multiple rounds can revert when a round in between is already filled.
               Resolve by sending multiple transactions of consecutive rounds if such issue exists.
               Fee on transfer tokens will not be supported.
     * @dev Players can still deposit into the round past the cutoff time. Only when other players start withdrawing
     *      or deposit into the next round, the current round will be cancelled and no longer accept deposits.
     */
    function enter(
        uint256 caveId,
        uint256 startingRoundId,
        uint256 numberOfRounds
    ) external payable nonReentrant whenNotPaused {
        Cave storage cave = caves[caveId];

        address enterCurrency = cave.enterCurrency;
        uint256 enterAmount = cave.enterAmount * numberOfRounds;

        if (enterCurrency == address(0)) {
            if (msg.value != enterAmount) {
                revert InvalidEnterAmount();
            }
        } else {
            if (msg.value != 0) {
                revert InvalidEnterCurrency();
            }
            TRANSFER_MANAGER.transferERC20(enterCurrency, msg.sender, address(this), enterAmount);
        }

        _enter(caveId, startingRoundId, numberOfRounds);
    }

    /**
     * @inheritdoc IPokeTheBear
     * @dev Player index starts from 1 as the array has a fixed length of 32 and
     *      0 is used to indicate an empty slot.
     */
    function reveal(uint256 requestId, uint256 playerIndices, bytes32 salt) external whenNotPaused {
        RandomnessRequest storage randomnessRequest = randomnessRequests[requestId];
        uint256 caveId = randomnessRequest.caveId;
        uint256 roundId = randomnessRequest.roundId;

        Round storage round = rounds[caveId][roundId];
        if (round.status != RoundStatus.Drawn) {
            revert InvalidRoundStatus();
        }

        if (keccak256(abi.encodePacked(playerIndices, salt)) != round.commitment) {
            revert HashedPlayerIndicesDoesNotMatchCommitment();
        }

        uint256 numberOfPlayers = round.players.length;
        uint256 losingIndex = (randomnessRequest.randomWord % numberOfPlayers) + 1;

        // Check numbers are nonrepeating and within the range
        uint256 playerIndicesBitmap;
        for (uint256 i; i < numberOfPlayers; ) {
            uint8 playerIndex = uint8(playerIndices >> (i * 8));

            // Player index starts from 1
            if (playerIndex == 0 || playerIndex > numberOfPlayers) {
                revert InvalidPlayerIndex(caveId, roundId);
            }

            uint256 bitmask = 1 << playerIndex;

            if (playerIndicesBitmap & bitmask != 0) {
                revert RepeatingPlayerIndex();
            }

            playerIndicesBitmap |= bitmask;

            round.playerIndices[i] = playerIndex;

            if (playerIndex == losingIndex) {
                round.players[i].isLoser = true;
            }

            unchecked {
                ++i;
            }
        }

        round.salt = salt;
        round.status = RoundStatus.Revealed;

        emit RoundStatusUpdated(caveId, roundId, RoundStatus.Revealed);

        Cave storage cave = caves[caveId];
        _transferTokens(
            protocolFeeRecipient,
            cave.enterCurrency,
            (cave.enterAmount * cave.protocolFeeBp) / ONE_HUNDRED_PERCENT_IN_BASIS_POINTS
        );

        _open(caveId, _unsafeAdd(roundId, 1));
    }

    /**
     * @inheritdoc IPokeTheBear
     */
    function refund(WithdrawalCalldata[] calldata refundCalldataArray) external nonReentrant whenNotPaused {
        TransferAccumulator memory transferAccumulator;
        uint256 refundCount = refundCalldataArray.length;

        Withdrawal[] memory withdrawalEventData = new Withdrawal[](refundCount);

        for (uint256 i; i < refundCount; ) {
            WithdrawalCalldata calldata refundCalldata = refundCalldataArray[i];
            uint256 caveId = refundCalldata.caveId;
            Cave storage cave = caves[caveId];
            uint256 roundsCount = refundCalldata.playerDetails.length;

            Withdrawal memory withdrawal = withdrawalEventData[i];
            withdrawal.caveId = caveId;
            withdrawal.roundIds = new uint256[](roundsCount);

            for (uint256 j; j < roundsCount; ) {
                PlayerWithdrawalCalldata calldata playerDetails = refundCalldata.playerDetails[j];
                uint256 roundId = playerDetails.roundId;

                Round storage round = rounds[caveId][roundId];
                RoundStatus roundStatus = round.status;
                uint256 currentNumberOfPlayers = round.players.length;

                {
                    if (roundStatus < RoundStatus.Revealed) {
                        if (!_cancellable(round, roundStatus, cave.playersPerRound, currentNumberOfPlayers)) {
                            revert InvalidRoundStatus();
                        }
                        _cancel(caveId, roundId);
                    }

                    uint256 playerIndex = playerDetails.playerIndex;
                    if (playerIndex >= currentNumberOfPlayers) {
                        revert InvalidPlayerIndex(caveId, roundId);
                    }

                    Player storage player = round.players[playerIndex];
                    _validatePlayerCanWithdraw(caveId, roundId, player);
                    player.withdrawn = true;
                }

                withdrawal.roundIds[j] = roundId;

                unchecked {
                    ++j;
                }
            }

            _accumulateOrTransferTokenOut(cave.enterAmount * roundsCount, cave.enterCurrency, transferAccumulator);

            unchecked {
                ++i;
            }
        }

        if (transferAccumulator.amount != 0) {
            _transferTokens(msg.sender, transferAccumulator.tokenAddress, transferAccumulator.amount);
        }

        emit DepositsRefunded(withdrawalEventData, msg.sender);
    }

    /**
     * @inheritdoc IPokeTheBear
     * @dev If a player chooses to rollover his prizes, only the principal is rolled over. The profit is
     *      always sent back to the player.
     */
    function rollover(RolloverCalldata[] calldata rolloverCalldataArray) external payable nonReentrant whenNotPaused {
        TransferAccumulator memory entryAccumulator;
        TransferAccumulator memory prizeAccumulator;
        Rollover[] memory rolloverEventData = new Rollover[](rolloverCalldataArray.length);

        uint256 msgValueLeft = msg.value;
        for (uint256 i; i < rolloverCalldataArray.length; ) {
            RolloverCalldata calldata rolloverCalldata = rolloverCalldataArray[i];
            uint256 roundsCount = rolloverCalldata.playerDetails.length;
            if (roundsCount == 0) {
                revert InvalidPlayerDetails();
            }

            uint256 caveId = rolloverCalldata.caveId;
            Cave storage cave = caves[caveId];
            uint256 numberOfExtraRoundsToEnter = rolloverCalldata.numberOfExtraRoundsToEnter;
            address enterCurrency = cave.enterCurrency;

            // Enter extra rounds
            if (numberOfExtraRoundsToEnter != 0) {
                if (enterCurrency == address(0)) {
                    msgValueLeft -= cave.enterAmount * numberOfExtraRoundsToEnter;
                } else {
                    if (enterCurrency == entryAccumulator.tokenAddress) {
                        entryAccumulator.amount += cave.enterAmount * numberOfExtraRoundsToEnter;
                    } else {
                        if (entryAccumulator.amount != 0) {
                            TRANSFER_MANAGER.transferERC20(
                                entryAccumulator.tokenAddress,
                                msg.sender,
                                address(this),
                                entryAccumulator.amount
                            );
                        }

                        entryAccumulator.tokenAddress = enterCurrency;
                        entryAccumulator.amount = cave.enterAmount * numberOfExtraRoundsToEnter;
                    }
                }
            }

            Rollover memory rolloverEvent = rolloverEventData[i];
            rolloverEvent.caveId = caveId;
            rolloverEvent.rolledOverRoundIds = new uint256[](roundsCount);

            uint256 prizeAmount;

            for (uint256 j; j < roundsCount; ) {
                PlayerWithdrawalCalldata calldata playerDetails = rolloverCalldata.playerDetails[j];

                RoundStatus roundStatus = _handleRolloverRound(playerDetails, caveId, cave.playersPerRound);

                if (roundStatus == RoundStatus.Revealed) {
                    prizeAmount += _prizeAmount(cave);
                }

                rolloverEvent.rolledOverRoundIds[j] = playerDetails.roundId;

                unchecked {
                    ++j;
                }
            }

            uint256 startingRoundId = rolloverCalldata.startingRoundId;
            rolloverEvent.rollingOverToRoundIdStart = startingRoundId;

            _enter({
                caveId: caveId,
                startingRoundId: startingRoundId,
                numberOfRounds: roundsCount + numberOfExtraRoundsToEnter
            });

            if (prizeAmount != 0) {
                _accumulateOrTransferTokenOut(prizeAmount, enterCurrency, prizeAccumulator);
            }

            unchecked {
                ++i;
            }
        }

        if (msgValueLeft != 0) {
            revert InvalidEnterAmount();
        }

        if (entryAccumulator.amount != 0) {
            TRANSFER_MANAGER.transferERC20(
                entryAccumulator.tokenAddress,
                msg.sender,
                address(this),
                entryAccumulator.amount
            );
        }

        if (prizeAccumulator.amount != 0) {
            _transferTokens(msg.sender, prizeAccumulator.tokenAddress, prizeAccumulator.amount);
        }

        emit DepositsRolledOver(rolloverEventData, msg.sender);
    }

    /**
     * @inheritdoc IPokeTheBear
     */
    function claimPrizes(WithdrawalCalldata[] calldata claimPrizeCalldataArray) external nonReentrant whenNotPaused {
        TransferAccumulator memory transferAccumulator;
        uint256 claimPrizeCount = claimPrizeCalldataArray.length;

        Withdrawal[] memory withdrawalEventData = new Withdrawal[](claimPrizeCount);

        for (uint256 i; i < claimPrizeCount; ) {
            WithdrawalCalldata calldata claimPrizeCalldata = claimPrizeCalldataArray[i];
            uint256 caveId = claimPrizeCalldata.caveId;

            Cave storage cave = caves[caveId];
            uint256 roundAmount = cave.enterAmount + _prizeAmount(cave);

            PlayerWithdrawalCalldata[] calldata playerDetailsArray = claimPrizeCalldata.playerDetails;
            uint256 roundsCount = playerDetailsArray.length;

            Withdrawal memory withdrawal = withdrawalEventData[i];
            withdrawal.caveId = caveId;
            withdrawal.roundIds = new uint256[](roundsCount);

            for (uint256 j; j < roundsCount; ) {
                PlayerWithdrawalCalldata calldata playerDetails = playerDetailsArray[j];
                uint256 roundId = playerDetails.roundId;

                Round storage round = rounds[caveId][roundId];
                if (round.status != RoundStatus.Revealed) {
                    revert InvalidRoundStatus();
                }

                Player storage player = round.players[playerDetails.playerIndex];
                _validatePlayerCanWithdraw(caveId, roundId, player);

                player.withdrawn = true;

                withdrawal.roundIds[j] = roundId;

                unchecked {
                    ++j;
                }
            }

            _accumulateOrTransferTokenOut(roundAmount * roundsCount, cave.enterCurrency, transferAccumulator);

            unchecked {
                ++i;
            }
        }

        if (transferAccumulator.amount != 0) {
            _transferTokens(msg.sender, transferAccumulator.tokenAddress, transferAccumulator.amount);
        }

        emit PrizesClaimed(withdrawalEventData, msg.sender);
    }

    /**
     * @inheritdoc IPokeTheBear
     */
    function cancel(uint256 caveId) external nonReentrant {
        Cave storage cave = caves[caveId];
        uint40 roundsCount = cave.roundsCount;
        Round storage round = rounds[caveId][roundsCount];
        if (!_cancellable(round, round.status, cave.playersPerRound, round.players.length)) {
            revert NotCancellable();
        }
        _cancel(caveId, roundsCount);
    }

    /**
     * @inheritdoc IPokeTheBear
     */
    function cancel(uint256 caveId, uint256 numberOfRounds) external nonReentrant whenPaused {
        _validateIsOwner();

        Cave storage cave = caves[caveId];
        uint256 startingRoundId = cave.roundsCount;
        uint256 lastRoundId = startingRoundId + numberOfRounds - 1;

        if (numberOfRounds == 0 || lastRoundId > cave.lastCommittedRoundId) {
            revert NotCancellable();
        }

        for (uint256 roundId = startingRoundId; roundId <= lastRoundId; ) {
            rounds[caveId][roundId].status = RoundStatus.Cancelled;
            unchecked {
                ++roundId;
            }
        }

        cave.roundsCount = uint40(lastRoundId);

        emit RoundsCancelled(caveId, startingRoundId, numberOfRounds);
    }

    function getRound(
        uint256 caveId,
        uint256 roundId
    )
        external
        view
        returns (
            RoundStatus status,
            uint40 cutoffTime,
            uint40 drawnAt,
            bytes32 commitment,
            bytes32 salt,
            uint8[32] memory playerIndices,
            Player[] memory players
        )
    {
        Round memory round = rounds[caveId][roundId];
        return (
            round.status,
            round.cutoffTime,
            round.drawnAt,
            round.commitment,
            round.salt,
            round.playerIndices,
            round.players
        );
    }

    /**
     * @dev Checks if the round is cancellable. A round is cancellable if its status is Cancelled,
     *      its status is Open but it has passed its cutoff time, its status is Drawing but Chainlink VRF
     *      callback did not happen on time, or its status is Drawn but the result was not revealed.
     * @param caveId The ID of the cave.
     * @param roundId The ID of the round.
     */
    function cancellable(uint256 caveId, uint256 roundId) external view returns (bool) {
        Round storage round = rounds[caveId][roundId];
        return _cancellable(round, round.status, caves[caveId].playersPerRound, round.players.length);
    }

    /**
     * @inheritdoc IPokeTheBear
     */
    function togglePaused() external {
        _validateIsOwner();
        paused() ? _unpause() : _pause();
    }

    /**
     * @inheritdoc IPokeTheBear
     */
    function isPlayerInRound(uint256 caveId, uint256 roundId, address player) public view returns (bool) {
        uint256 bucket = roundId >> 8;
        uint256 slot = 1 << (roundId & 0xff);
        return playerParticipations[player][caveId][bucket] & slot != 0;
    }

    /**
     * @param requestId The ID of the request
     * @param randomWords The random words returned by Chainlink
     */
    function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal override {
        if (randomnessRequests[requestId].exists) {
            uint256 caveId = randomnessRequests[requestId].caveId;
            uint256 roundId = randomnessRequests[requestId].roundId;

            Round storage round = rounds[caveId][roundId];

            if (round.status == RoundStatus.Drawing) {
                round.status = RoundStatus.Drawn;
                randomnessRequests[requestId].randomWord = randomWords[0];

                emit RoundStatusUpdated(caveId, roundId, RoundStatus.Drawn);
            }
        }
    }

    /**
     * @dev This function is used to enter rounds, charging is done outside of this function.
     * @param caveId The ID of the cave.
     * @param startingRoundId The ID of the starting round.
     * @param numberOfRounds The number of rounds to enter.
     */
    function _enter(uint256 caveId, uint256 startingRoundId, uint256 numberOfRounds) private {
        if (startingRoundId == 0 || numberOfRounds == 0) {
            revert InvalidRoundParameters();
        }

        Cave storage cave = caves[caveId];

        if (!cave.isActive) {
            revert InactiveCave();
        }

        uint256 endingRoundIdPlusOne = startingRoundId + numberOfRounds;

        if (_unsafeSubtract(endingRoundIdPlusOne, 1) > cave.lastCommittedRoundId) {
            revert CommitmentNotAvailable();
        }

        Round storage startingRound = rounds[caveId][startingRoundId];
        // We just need to check the first round's status. If the first round is open,
        // subsequent rounds will not be drawn/cancelled as well.
        RoundStatus startingRoundStatus = startingRound.status;
        if (startingRoundStatus > RoundStatus.Open) {
            revert RoundCannotBeEntered(caveId, startingRoundId);
        }

        uint8 playersPerRound = cave.playersPerRound;

        if (startingRoundStatus == RoundStatus.None) {
            if (startingRoundId > 1) {
                uint256 lastRoundId = _unsafeSubtract(startingRoundId, 1);
                Round storage lastRound = rounds[caveId][lastRoundId];
                if (_cancellable(lastRound, lastRound.status, playersPerRound, lastRound.players.length)) {
                    _cancel(caveId, lastRoundId);
                    // The current round is now open (_cancel calls _open), we can manually change startingRoundStatus without touching the storage.
                    startingRoundStatus = RoundStatus.Open;
                }
            }
        }

        for (uint256 roundId = startingRoundId; roundId < endingRoundIdPlusOne; ) {
            if (isPlayerInRound(caveId, roundId, msg.sender)) {
                revert PlayerAlreadyParticipated(caveId, roundId, msg.sender);
            }
            // Starting round already exists from outside the loop so we can reuse it for gas efficiency.
            Round storage round = roundId == startingRoundId ? startingRound : rounds[caveId][roundId];
            uint256 newNumberOfPlayers = _unsafeAdd(round.players.length, 1);
            // This is not be a problem for the current open round, but this
            // can be a problem for future rounds.
            if (newNumberOfPlayers > playersPerRound) {
                revert RoundCannotBeEntered(caveId, roundId);
            }

            round.players.push(Player({addr: msg.sender, isLoser: false, withdrawn: false}));
            _markPlayerInRound(caveId, roundId, msg.sender);

            // Start countdown only for the current round and only if it is the first player.
            if (roundId == startingRoundId) {
                if (startingRoundStatus == RoundStatus.Open) {
                    if (round.cutoffTime == 0) {
                        round.cutoffTime = uint40(block.timestamp) + cave.roundDuration;
                    }

                    if (newNumberOfPlayers == playersPerRound) {
                        _draw(caveId, roundId);
                    }
                }
            }

            unchecked {
                ++roundId;
            }
        }

        emit RoundsEntered(caveId, startingRoundId, numberOfRounds, msg.sender);
    }

    /**
     * @param caveId The ID of the cave.
     * @param roundId The ID of the round to draw.
     */
    function _draw(uint256 caveId, uint256 roundId) private {
        rounds[caveId][roundId].status = RoundStatus.Drawing;
        rounds[caveId][roundId].drawnAt = uint40(block.timestamp);

        uint256 requestId = VRF_COORDINATOR.requestRandomWords({
            keyHash: KEY_HASH,
            subId: SUBSCRIPTION_ID,
            minimumRequestConfirmations: uint16(3),
            callbackGasLimit: uint32(500_000),
            numWords: uint32(1)
        });

        if (randomnessRequests[requestId].exists) {
            revert RandomnessRequestAlreadyExists();
        }

        randomnessRequests[requestId].exists = true;
        randomnessRequests[requestId].caveId = uint40(caveId);
        randomnessRequests[requestId].roundId = uint40(roundId);

        emit RandomnessRequested(caveId, roundId, requestId);
        emit RoundStatusUpdated(caveId, roundId, RoundStatus.Drawing);
    }

    /**
     * @dev This function cancels the current round and opens the next round.
     * @param caveId The ID of the cave.
     * @param roundId The ID of the round to cancel.
     */
    function _cancel(uint256 caveId, uint256 roundId) private {
        rounds[caveId][roundId].status = RoundStatus.Cancelled;
        emit RoundStatusUpdated(caveId, roundId, RoundStatus.Cancelled);
        _open(caveId, _unsafeAdd(roundId, 1));
    }

    /**
     * @dev This function opens a new round.
     *      If the new round is already fully filled, it will be drawn immediately.
     *      If the round is partially filled, the countdown starts.
     * @param caveId The ID of the cave.
     * @param roundId The ID of the round to open.
     */
    function _open(uint256 caveId, uint256 roundId) private {
        Round storage round = rounds[caveId][roundId];
        uint256 playersCount = round.players.length;
        Cave storage cave = caves[caveId];

        if (playersCount == cave.playersPerRound) {
            _draw(caveId, roundId);
        } else {
            round.status = RoundStatus.Open;
            cave.roundsCount = uint40(roundId);
            emit RoundStatusUpdated(caveId, roundId, RoundStatus.Open);

            if (playersCount != 0) {
                round.cutoffTime = uint40(block.timestamp) + cave.roundDuration;
            }
        }
    }

    /**
     * @param playerDetails Information about the player to rollover.
     * @param caveId The ID of the cave.
     * @param playersPerRound The number of required players.
     */
    function _handleRolloverRound(
        PlayerWithdrawalCalldata calldata playerDetails,
        uint256 caveId,
        uint8 playersPerRound
    ) private returns (RoundStatus roundStatus) {
        uint256 roundId = playerDetails.roundId;
        uint256 playerIndex = playerDetails.playerIndex;
        Round storage round = rounds[caveId][roundId];
        roundStatus = round.status;
        uint256 currentNumberOfPlayers = round.players.length;

        if (roundStatus < RoundStatus.Revealed) {
            if (!_cancellable(round, roundStatus, playersPerRound, currentNumberOfPlayers)) {
                revert InvalidRoundStatus();
            }
            _cancel(caveId, roundId);
        }

        if (playerIndex >= currentNumberOfPlayers) {
            revert InvalidPlayerIndex(caveId, roundId);
        }

        Player storage player = round.players[playerIndex];
        _validatePlayerCanWithdraw(caveId, roundId, player);
        player.withdrawn = true;
    }

    /**
     * @param recipient The recipient of the transfer.
     * @param currency The transfer currency.
     * @param amount The transfer amount.
     */
    function _transferTokens(address recipient, address currency, uint256 amount) private {
        if (currency == address(0)) {
            _transferETHAndWrapIfFailWithGasLimit(WRAPPED_NATIVE_TOKEN, recipient, amount, gasleft());
        } else {
            _executeERC20DirectTransfer(currency, recipient, amount);
        }
    }

    /**
     * @param tokenAmount The amount of tokens to accumulate.
     * @param tokenAddress The token address to accumulate.
     * @param transferAccumulator The transfer accumulator state so far.
     */
    function _accumulateOrTransferTokenOut(
        uint256 tokenAmount,
        address tokenAddress,
        TransferAccumulator memory transferAccumulator
    ) private {
        if (tokenAddress == transferAccumulator.tokenAddress) {
            transferAccumulator.amount += tokenAmount;
        } else {
            if (transferAccumulator.amount != 0) {
                _transferTokens(msg.sender, transferAccumulator.tokenAddress, transferAccumulator.amount);
            }

            transferAccumulator.tokenAddress = tokenAddress;
            transferAccumulator.amount = tokenAmount;
        }
    }

    /**
     * @notice Marks a player as participated in a round.
     * @dev A round starts with the ID 1 and the bitmap starts with the index 0, therefore we need to subtract 1.
     * @param caveId The ID of the cave.
     * @param roundId The ID of the round.
     * @param player The address of the player.
     */
    function _markPlayerInRound(uint256 caveId, uint256 roundId, address player) private {
        uint256 bucket = roundId >> 8;
        uint256 slot = 1 << (roundId & 0xff);
        playerParticipations[player][caveId][bucket] |= slot;
    }

    /**
     * @notice Checks if the round data fulfills an expired open round.
     * @param roundStatus The status of the round.
     * @param cutoffTime The cutoff time of the round.
     * @param currentNumberOfPlayers The current number of players in the round.
     * @param playersPerRound The maximum number of players in a round.
     */
    function _isExpiredOpenRound(
        RoundStatus roundStatus,
        uint40 cutoffTime,
        uint256 currentNumberOfPlayers,
        uint8 playersPerRound
    ) private view returns (bool) {
        return
            roundStatus == RoundStatus.Open &&
            cutoffTime != 0 &&
            block.timestamp >= cutoffTime &&
            currentNumberOfPlayers < playersPerRound;
    }

    /**
     * @notice Checks if the round is pending VRF or commitment reveal for too long. We tolerate a delay of up to 1 day.
     * @param roundStatus The status of the round.
     * @param round The round to check.
     */
    function _pendingVRFOrRevealForTooLong(RoundStatus roundStatus, Round storage round) private view returns (bool) {
        return
            (roundStatus == RoundStatus.Drawing || roundStatus == RoundStatus.Drawn) &&
            block.timestamp >= round.drawnAt + 1 days;
    }

    /**
     * @dev player.isLoser is a check for claimPrize only, but it is also useful to act as an invariant for refund.
     * @param caveId The ID of the cave.
     * @param roundId The ID of the round.
     * @param player The player.
     */
    function _validatePlayerCanWithdraw(uint256 caveId, uint256 roundId, Player storage player) private view {
        if (player.isLoser || player.withdrawn || player.addr != msg.sender) {
            revert IneligibleToWithdraw(caveId, roundId);
        }
    }

    /**
     * @dev Checks if the round is cancellable. A round is cancellable if its status is Cancelled,
     *      its status is Open but it has passed its cutoff time, its status is Drawing but Chainlink VRF
     *      callback did not happen on time, or its status is Drawn but the result was not revealed.
     * @param round The round to check.
     * @param roundStatus The status of the round.
     * @param playersPerRound The maximum number of players in the round.
     * @param currentNumberOfPlayers The current number of players in the round.
     */
    function _cancellable(
        Round storage round,
        RoundStatus roundStatus,
        uint8 playersPerRound,
        uint256 currentNumberOfPlayers
    ) private view returns (bool) {
        return
            _isExpiredOpenRound(roundStatus, round.cutoffTime, currentNumberOfPlayers, playersPerRound) ||
            _pendingVRFOrRevealForTooLong(roundStatus, round);
    }

    /**
     * @param _protocolFeeRecipient The new protocol fee recipient address
     */
    function _updateProtocolFeeRecipient(address _protocolFeeRecipient) internal {
        if (_protocolFeeRecipient == address(0)) {
            revert InvalidValue();
        }
        protocolFeeRecipient = _protocolFeeRecipient;
        emit ProtocolFeeRecipientUpdated(_protocolFeeRecipient);
    }

    /**
     * @notice Calculates the prize amount.
     * @param cave The cave to calculate the prize amount.
     */
    function _prizeAmount(Cave storage cave) private view returns (uint256) {
        return
            (cave.enterAmount * (_unsafeSubtract(ONE_HUNDRED_PERCENT_IN_BASIS_POINTS, cave.protocolFeeBp))) /
            ONE_HUNDRED_PERCENT_IN_BASIS_POINTS /
            _unsafeSubtract(cave.playersPerRound, 1);
    }

    /**
     * Unsafe math functions.
     */

    function _unsafeAdd(uint256 a, uint256 b) private pure returns (uint256) {
        unchecked {
            return a + b;
        }
    }

    function _unsafeSubtract(uint256 a, uint256 b) private pure returns (uint256) {
        unchecked {
            return a - b;
        }
    }

    function _validateIsOwner() private view {
        if (!hasRole(DEFAULT_ADMIN_ROLE, msg.sender)) {
            revert NotOwner();
        }
    }

    function _validateIsOperator() private view {
        if (!hasRole(OPERATOR_ROLE, msg.sender)) {
            revert NotOperator();
        }
    }
}

File 2 of 20 : LowLevelWETH.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

// Interfaces
import {IWETH} from "../interfaces/generic/IWETH.sol";

/**
 * @title LowLevelWETH
 * @notice This contract contains a function to transfer ETH with an option to wrap to WETH.
 *         If the ETH transfer fails within a gas limit, the amount in ETH is wrapped to WETH and then transferred.
 * @author LooksRare protocol team (👀,💎)
 */
contract LowLevelWETH {
    /**
     * @notice It transfers ETH to a recipient with a specified gas limit.
     *         If the original transfers fails, it wraps to WETH and transfers the WETH to recipient.
     * @param _WETH WETH address
     * @param _to Recipient address
     * @param _amount Amount to transfer
     * @param _gasLimit Gas limit to perform the ETH transfer
     */
    function _transferETHAndWrapIfFailWithGasLimit(
        address _WETH,
        address _to,
        uint256 _amount,
        uint256 _gasLimit
    ) internal {
        bool status;

        assembly {
            status := call(_gasLimit, _to, _amount, 0, 0, 0, 0)
        }

        if (!status) {
            IWETH(_WETH).deposit{value: _amount}();
            IWETH(_WETH).transfer(_to, _amount);
        }
    }
}

File 3 of 20 : LowLevelERC20Transfer.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

// Interfaces
import {IERC20} from "../interfaces/generic/IERC20.sol";

// Errors
import {ERC20TransferFail, ERC20TransferFromFail} from "../errors/LowLevelErrors.sol";
import {NotAContract} from "../errors/GenericErrors.sol";

/**
 * @title LowLevelERC20Transfer
 * @notice This contract contains low-level calls to transfer ERC20 tokens.
 * @author LooksRare protocol team (👀,💎)
 */
contract LowLevelERC20Transfer {
    /**
     * @notice Execute ERC20 transferFrom
     * @param currency Currency address
     * @param from Sender address
     * @param to Recipient address
     * @param amount Amount to transfer
     */
    function _executeERC20TransferFrom(address currency, address from, address to, uint256 amount) internal {
        if (currency.code.length == 0) {
            revert NotAContract();
        }

        (bool status, bytes memory data) = currency.call(abi.encodeCall(IERC20.transferFrom, (from, to, amount)));

        if (!status) {
            revert ERC20TransferFromFail();
        }

        if (data.length > 0) {
            if (!abi.decode(data, (bool))) {
                revert ERC20TransferFromFail();
            }
        }
    }

    /**
     * @notice Execute ERC20 (direct) transfer
     * @param currency Currency address
     * @param to Recipient address
     * @param amount Amount to transfer
     */
    function _executeERC20DirectTransfer(address currency, address to, uint256 amount) internal {
        if (currency.code.length == 0) {
            revert NotAContract();
        }

        (bool status, bytes memory data) = currency.call(abi.encodeCall(IERC20.transfer, (to, amount)));

        if (!status) {
            revert ERC20TransferFail();
        }

        if (data.length > 0) {
            if (!abi.decode(data, (bool))) {
                revert ERC20TransferFail();
            }
        }
    }
}

File 4 of 20 : PackableReentrancyGuard.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

// Interfaces
import {IReentrancyGuard} from "./interfaces/IReentrancyGuard.sol";

/**
 * @title PackableReentrancyGuard
 * @notice This contract protects against reentrancy attacks.
 *         It is adjusted from OpenZeppelin.
 *         The only difference between this contract and ReentrancyGuard
 *         is that _status is uint8 instead of uint256 so that it can be
 *         packed with other contracts' storage variables.
 * @author LooksRare protocol team (👀,💎)
 */
abstract contract PackableReentrancyGuard is IReentrancyGuard {
    uint8 private _status;

    /**
     * @notice Modifier to wrap functions to prevent reentrancy calls.
     */
    modifier nonReentrant() {
        if (_status == 2) {
            revert ReentrancyFail();
        }

        _status = 2;
        _;
        _status = 1;
    }

    constructor() {
        _status = 1;
    }
}

File 5 of 20 : Pausable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

/**
 * @title Pausable
 * @notice This contract makes it possible to pause the contract.
 *         It is adjusted from OpenZeppelin.
 * @author LooksRare protocol team (👀,💎)
 */
abstract contract Pausable {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    error IsPaused();
    error NotPaused();

    bool private _paused;

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        _requireNotPaused();
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        _requirePaused();
        _;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @dev Throws if the contract is paused.
     */
    function _requireNotPaused() internal view virtual {
        if (paused()) {
            revert IsPaused();
        }
    }

    /**
     * @dev Throws if the contract is not paused.
     */
    function _requirePaused() internal view virtual {
        if (!paused()) {
            revert NotPaused();
        }
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(msg.sender);
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(msg.sender);
    }
}

File 6 of 20 : ITransferManager.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

// Enums
import {TokenType} from "../enums/TokenType.sol";

/**
 * @title ITransferManager
 * @author LooksRare protocol team (👀,💎)
 */
interface ITransferManager {
    /**
     * @notice This struct is only used for transferBatchItemsAcrossCollections.
     * @param tokenAddress Token address
     * @param tokenType 0 for ERC721, 1 for ERC1155
     * @param itemIds Array of item ids to transfer
     * @param amounts Array of amounts to transfer
     */
    struct BatchTransferItem {
        address tokenAddress;
        TokenType tokenType;
        uint256[] itemIds;
        uint256[] amounts;
    }

    /**
     * @notice It is emitted if operators' approvals to transfer NFTs are granted by a user.
     * @param user Address of the user
     * @param operators Array of operator addresses
     */
    event ApprovalsGranted(address user, address[] operators);

    /**
     * @notice It is emitted if operators' approvals to transfer NFTs are revoked by a user.
     * @param user Address of the user
     * @param operators Array of operator addresses
     */
    event ApprovalsRemoved(address user, address[] operators);

    /**
     * @notice It is emitted if a new operator is added to the global allowlist.
     * @param operator Operator address
     */
    event OperatorAllowed(address operator);

    /**
     * @notice It is emitted if an operator is removed from the global allowlist.
     * @param operator Operator address
     */
    event OperatorRemoved(address operator);

    /**
     * @notice It is returned if the operator to approve has already been approved by the user.
     */
    error OperatorAlreadyApprovedByUser();

    /**
     * @notice It is returned if the operator to revoke has not been previously approved by the user.
     */
    error OperatorNotApprovedByUser();

    /**
     * @notice It is returned if the transfer caller is already allowed by the owner.
     * @dev This error can only be returned for owner operations.
     */
    error OperatorAlreadyAllowed();

    /**
     * @notice It is returned if the operator to approve is not in the global allowlist defined by the owner.
     * @dev This error can be returned if the user tries to grant approval to an operator address not in the
     *      allowlist or if the owner tries to remove the operator from the global allowlist.
     */
    error OperatorNotAllowed();

    /**
     * @notice It is returned if the transfer caller is invalid.
     *         For a transfer called to be valid, the operator must be in the global allowlist and
     *         approved by the 'from' user.
     */
    error TransferCallerInvalid();

    /**
     * @notice This function transfers ERC20 tokens.
     * @param tokenAddress Token address
     * @param from Sender address
     * @param to Recipient address
     * @param amount amount
     */
    function transferERC20(
        address tokenAddress,
        address from,
        address to,
        uint256 amount
    ) external;

    /**
     * @notice This function transfers a single item for a single ERC721 collection.
     * @param tokenAddress Token address
     * @param from Sender address
     * @param to Recipient address
     * @param itemId Item ID
     */
    function transferItemERC721(
        address tokenAddress,
        address from,
        address to,
        uint256 itemId
    ) external;

    /**
     * @notice This function transfers items for a single ERC721 collection.
     * @param tokenAddress Token address
     * @param from Sender address
     * @param to Recipient address
     * @param itemIds Array of itemIds
     * @param amounts Array of amounts
     */
    function transferItemsERC721(
        address tokenAddress,
        address from,
        address to,
        uint256[] calldata itemIds,
        uint256[] calldata amounts
    ) external;

    /**
     * @notice This function transfers a single item for a single ERC1155 collection.
     * @param tokenAddress Token address
     * @param from Sender address
     * @param to Recipient address
     * @param itemId Item ID
     * @param amount Amount
     */
    function transferItemERC1155(
        address tokenAddress,
        address from,
        address to,
        uint256 itemId,
        uint256 amount
    ) external;

    /**
     * @notice This function transfers items for a single ERC1155 collection.
     * @param tokenAddress Token address
     * @param from Sender address
     * @param to Recipient address
     * @param itemIds Array of itemIds
     * @param amounts Array of amounts
     * @dev It does not allow batch transferring if from = msg.sender since native function should be used.
     */
    function transferItemsERC1155(
        address tokenAddress,
        address from,
        address to,
        uint256[] calldata itemIds,
        uint256[] calldata amounts
    ) external;

    /**
     * @notice This function transfers items across an array of tokens that can be ERC20, ERC721 and ERC1155.
     * @param items Array of BatchTransferItem
     * @param from Sender address
     * @param to Recipient address
     */
    function transferBatchItemsAcrossCollections(
        BatchTransferItem[] calldata items,
        address from,
        address to
    ) external;

    /**
     * @notice This function allows a user to grant approvals for an array of operators.
     *         Users cannot grant approvals if the operator is not allowed by this contract's owner.
     * @param operators Array of operator addresses
     * @dev Each operator address must be globally allowed to be approved.
     */
    function grantApprovals(address[] calldata operators) external;

    /**
     * @notice This function allows a user to revoke existing approvals for an array of operators.
     * @param operators Array of operator addresses
     * @dev Each operator address must be approved at the user level to be revoked.
     */
    function revokeApprovals(address[] calldata operators) external;

    /**
     * @notice This function allows an operator to be added for the shared transfer system.
     *         Once the operator is allowed, users can grant NFT approvals to this operator.
     * @param operator Operator address to allow
     * @dev Only callable by owner.
     */
    function allowOperator(address operator) external;

    /**
     * @notice This function allows the user to remove an operator for the shared transfer system.
     * @param operator Operator address to remove
     * @dev Only callable by owner.
     */
    function removeOperator(address operator) external;

    /**
     * @notice This returns whether the user has approved the operator address.
     * The first address is the user and the second address is the operator.
     */
    function hasUserApprovedOperator(address user, address operator) external view returns (bool);
}

File 7 of 20 : AccessControl.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)

pragma solidity ^0.8.20;

import {IAccessControl} from "./IAccessControl.sol";
import {Context} from "../utils/Context.sol";
import {ERC165} from "../utils/introspection/ERC165.sol";

/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms. This is a lightweight version that doesn't allow enumerating role
 * members except through off-chain means by accessing the contract event logs. Some
 * applications may benefit from on-chain enumerability, for those cases see
 * {AccessControlEnumerable}.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```solidity
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```solidity
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
 * to enforce additional security measures for this role.
 */
abstract contract AccessControl is Context, IAccessControl, ERC165 {
    struct RoleData {
        mapping(address account => bool) hasRole;
        bytes32 adminRole;
    }

    mapping(bytes32 role => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with an {AccessControlUnauthorizedAccount} error including the required role.
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role);
        _;
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view virtual returns (bool) {
        return _roles[role].hasRole[account];
    }

    /**
     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
     * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
     */
    function _checkRole(bytes32 role) internal view virtual {
        _checkRole(role, _msgSender());
    }

    /**
     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
     * is missing `role`.
     */
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!hasRole(role, account)) {
            revert AccessControlUnauthorizedAccount(account, role);
        }
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
        return _roles[role].adminRole;
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleGranted} event.
     */
    function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
        _grantRole(role, account);
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleRevoked} event.
     */
    function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
        _revokeRole(role, account);
    }

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been revoked `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `callerConfirmation`.
     *
     * May emit a {RoleRevoked} event.
     */
    function renounceRole(bytes32 role, address callerConfirmation) public virtual {
        if (callerConfirmation != _msgSender()) {
            revert AccessControlBadConfirmation();
        }

        _revokeRole(role, callerConfirmation);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        bytes32 previousAdminRole = getRoleAdmin(role);
        _roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    /**
     * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleGranted} event.
     */
    function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
        if (!hasRole(role, account)) {
            _roles[role].hasRole[account] = true;
            emit RoleGranted(role, account, _msgSender());
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleRevoked} event.
     */
    function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
        if (hasRole(role, account)) {
            _roles[role].hasRole[account] = false;
            emit RoleRevoked(role, account, _msgSender());
            return true;
        } else {
            return false;
        }
    }
}

File 8 of 20 : VRFCoordinatorV2Interface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface VRFCoordinatorV2Interface {
  /**
   * @notice Get configuration relevant for making requests
   * @return minimumRequestConfirmations global min for request confirmations
   * @return maxGasLimit global max for request gas limit
   * @return s_provingKeyHashes list of registered key hashes
   */
  function getRequestConfig()
    external
    view
    returns (
      uint16,
      uint32,
      bytes32[] memory
    );

  /**
   * @notice Request a set of random words.
   * @param keyHash - Corresponds to a particular oracle job which uses
   * that key for generating the VRF proof. Different keyHash's have different gas price
   * ceilings, so you can select a specific one to bound your maximum per request cost.
   * @param subId  - The ID of the VRF subscription. Must be funded
   * with the minimum subscription balance required for the selected keyHash.
   * @param minimumRequestConfirmations - How many blocks you'd like the
   * oracle to wait before responding to the request. See SECURITY CONSIDERATIONS
   * for why you may want to request more. The acceptable range is
   * [minimumRequestBlockConfirmations, 200].
   * @param callbackGasLimit - How much gas you'd like to receive in your
   * fulfillRandomWords callback. Note that gasleft() inside fulfillRandomWords
   * may be slightly less than this amount because of gas used calling the function
   * (argument decoding etc.), so you may need to request slightly more than you expect
   * to have inside fulfillRandomWords. The acceptable range is
   * [0, maxGasLimit]
   * @param numWords - The number of uint256 random values you'd like to receive
   * in your fulfillRandomWords callback. Note these numbers are expanded in a
   * secure way by the VRFCoordinator from a single random value supplied by the oracle.
   * @return requestId - A unique identifier of the request. Can be used to match
   * a request to a response in fulfillRandomWords.
   */
  function requestRandomWords(
    bytes32 keyHash,
    uint64 subId,
    uint16 minimumRequestConfirmations,
    uint32 callbackGasLimit,
    uint32 numWords
  ) external returns (uint256 requestId);

  /**
   * @notice Create a VRF subscription.
   * @return subId - A unique subscription id.
   * @dev You can manage the consumer set dynamically with addConsumer/removeConsumer.
   * @dev Note to fund the subscription, use transferAndCall. For example
   * @dev  LINKTOKEN.transferAndCall(
   * @dev    address(COORDINATOR),
   * @dev    amount,
   * @dev    abi.encode(subId));
   */
  function createSubscription() external returns (uint64 subId);

  /**
   * @notice Get a VRF subscription.
   * @param subId - ID of the subscription
   * @return balance - LINK balance of the subscription in juels.
   * @return reqCount - number of requests for this subscription, determines fee tier.
   * @return owner - owner of the subscription.
   * @return consumers - list of consumer address which are able to use this subscription.
   */
  function getSubscription(uint64 subId)
    external
    view
    returns (
      uint96 balance,
      uint64 reqCount,
      address owner,
      address[] memory consumers
    );

  /**
   * @notice Request subscription owner transfer.
   * @param subId - ID of the subscription
   * @param newOwner - proposed new owner of the subscription
   */
  function requestSubscriptionOwnerTransfer(uint64 subId, address newOwner) external;

  /**
   * @notice Request subscription owner transfer.
   * @param subId - ID of the subscription
   * @dev will revert if original owner of subId has
   * not requested that msg.sender become the new owner.
   */
  function acceptSubscriptionOwnerTransfer(uint64 subId) external;

  /**
   * @notice Add a consumer to a VRF subscription.
   * @param subId - ID of the subscription
   * @param consumer - New consumer which can use the subscription
   */
  function addConsumer(uint64 subId, address consumer) external;

  /**
   * @notice Remove a consumer from a VRF subscription.
   * @param subId - ID of the subscription
   * @param consumer - Consumer to remove from the subscription
   */
  function removeConsumer(uint64 subId, address consumer) external;

  /**
   * @notice Cancel a subscription
   * @param subId - ID of the subscription
   * @param to - Where to send the remaining LINK to
   */
  function cancelSubscription(uint64 subId, address to) external;

  /*
   * @notice Check to see if there exists a request commitment consumers
   * for all consumers and keyhashes for a given sub.
   * @param subId - ID of the subscription
   * @return true if there exists at least one unfulfilled request for the subscription, false
   * otherwise.
   */
  function pendingRequestExists(uint64 subId) external view returns (bool);
}

File 9 of 20 : VRFConsumerBaseV2.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/** ****************************************************************************
 * @notice Interface for contracts using VRF randomness
 * *****************************************************************************
 * @dev PURPOSE
 *
 * @dev Reggie the Random Oracle (not his real job) wants to provide randomness
 * @dev to Vera the verifier in such a way that Vera can be sure he's not
 * @dev making his output up to suit himself. Reggie provides Vera a public key
 * @dev to which he knows the secret key. Each time Vera provides a seed to
 * @dev Reggie, he gives back a value which is computed completely
 * @dev deterministically from the seed and the secret key.
 *
 * @dev Reggie provides a proof by which Vera can verify that the output was
 * @dev correctly computed once Reggie tells it to her, but without that proof,
 * @dev the output is indistinguishable to her from a uniform random sample
 * @dev from the output space.
 *
 * @dev The purpose of this contract is to make it easy for unrelated contracts
 * @dev to talk to Vera the verifier about the work Reggie is doing, to provide
 * @dev simple access to a verifiable source of randomness. It ensures 2 things:
 * @dev 1. The fulfillment came from the VRFCoordinator
 * @dev 2. The consumer contract implements fulfillRandomWords.
 * *****************************************************************************
 * @dev USAGE
 *
 * @dev Calling contracts must inherit from VRFConsumerBase, and can
 * @dev initialize VRFConsumerBase's attributes in their constructor as
 * @dev shown:
 *
 * @dev   contract VRFConsumer {
 * @dev     constructor(<other arguments>, address _vrfCoordinator, address _link)
 * @dev       VRFConsumerBase(_vrfCoordinator) public {
 * @dev         <initialization with other arguments goes here>
 * @dev       }
 * @dev   }
 *
 * @dev The oracle will have given you an ID for the VRF keypair they have
 * @dev committed to (let's call it keyHash). Create subscription, fund it
 * @dev and your consumer contract as a consumer of it (see VRFCoordinatorInterface
 * @dev subscription management functions).
 * @dev Call requestRandomWords(keyHash, subId, minimumRequestConfirmations,
 * @dev callbackGasLimit, numWords),
 * @dev see (VRFCoordinatorInterface for a description of the arguments).
 *
 * @dev Once the VRFCoordinator has received and validated the oracle's response
 * @dev to your request, it will call your contract's fulfillRandomWords method.
 *
 * @dev The randomness argument to fulfillRandomWords is a set of random words
 * @dev generated from your requestId and the blockHash of the request.
 *
 * @dev If your contract could have concurrent requests open, you can use the
 * @dev requestId returned from requestRandomWords to track which response is associated
 * @dev with which randomness request.
 * @dev See "SECURITY CONSIDERATIONS" for principles to keep in mind,
 * @dev if your contract could have multiple requests in flight simultaneously.
 *
 * @dev Colliding `requestId`s are cryptographically impossible as long as seeds
 * @dev differ.
 *
 * *****************************************************************************
 * @dev SECURITY CONSIDERATIONS
 *
 * @dev A method with the ability to call your fulfillRandomness method directly
 * @dev could spoof a VRF response with any random value, so it's critical that
 * @dev it cannot be directly called by anything other than this base contract
 * @dev (specifically, by the VRFConsumerBase.rawFulfillRandomness method).
 *
 * @dev For your users to trust that your contract's random behavior is free
 * @dev from malicious interference, it's best if you can write it so that all
 * @dev behaviors implied by a VRF response are executed *during* your
 * @dev fulfillRandomness method. If your contract must store the response (or
 * @dev anything derived from it) and use it later, you must ensure that any
 * @dev user-significant behavior which depends on that stored value cannot be
 * @dev manipulated by a subsequent VRF request.
 *
 * @dev Similarly, both miners and the VRF oracle itself have some influence
 * @dev over the order in which VRF responses appear on the blockchain, so if
 * @dev your contract could have multiple VRF requests in flight simultaneously,
 * @dev you must ensure that the order in which the VRF responses arrive cannot
 * @dev be used to manipulate your contract's user-significant behavior.
 *
 * @dev Since the block hash of the block which contains the requestRandomness
 * @dev call is mixed into the input to the VRF *last*, a sufficiently powerful
 * @dev miner could, in principle, fork the blockchain to evict the block
 * @dev containing the request, forcing the request to be included in a
 * @dev different block with a different hash, and therefore a different input
 * @dev to the VRF. However, such an attack would incur a substantial economic
 * @dev cost. This cost scales with the number of blocks the VRF oracle waits
 * @dev until it calls responds to a request. It is for this reason that
 * @dev that you can signal to an oracle you'd like them to wait longer before
 * @dev responding to the request (however this is not enforced in the contract
 * @dev and so remains effective only in the case of unmodified oracle software).
 */
abstract contract VRFConsumerBaseV2 {
  error OnlyCoordinatorCanFulfill(address have, address want);
  address private immutable vrfCoordinator;

  /**
   * @param _vrfCoordinator address of VRFCoordinator contract
   */
  constructor(address _vrfCoordinator) {
    vrfCoordinator = _vrfCoordinator;
  }

  /**
   * @notice fulfillRandomness handles the VRF response. Your contract must
   * @notice implement it. See "SECURITY CONSIDERATIONS" above for important
   * @notice principles to keep in mind when implementing your fulfillRandomness
   * @notice method.
   *
   * @dev VRFConsumerBaseV2 expects its subcontracts to have a method with this
   * @dev signature, and will call it once it has verified the proof
   * @dev associated with the randomness. (It is triggered via a call to
   * @dev rawFulfillRandomness, below.)
   *
   * @param requestId The Id initially returned by requestRandomness
   * @param randomWords the VRF output expanded to the requested number of words
   */
  function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal virtual;

  // rawFulfillRandomness is called by VRFCoordinator when it receives a valid VRF
  // proof. rawFulfillRandomness then calls fulfillRandomness, after validating
  // the origin of the call
  function rawFulfillRandomWords(uint256 requestId, uint256[] memory randomWords) external {
    if (msg.sender != vrfCoordinator) {
      revert OnlyCoordinatorCanFulfill(msg.sender, vrfCoordinator);
    }
    fulfillRandomWords(requestId, randomWords);
  }
}

File 10 of 20 : IPokeTheBear.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

interface IPokeTheBear {
    /**
     * @notice The status of a round.
     *         None: The round hasn't started yet.
     *         Open: The round is open for players to enter.
     *         Drawing: The round is being drawn using Chainlink VRF.
     *         Drawn: The round has been drawn. Chainlink VRF has returned a random number.
     *         Revealed: The loser has been revealed.
     *         Cancelled: The round has been cancelled.
     */
    enum RoundStatus {
        None,
        Open,
        Drawing,
        Drawn,
        Revealed,
        Cancelled
    }

    /**
     * @notice A player in a round.
     * @param addr The address of the player.
     * @param isLoser Whether the player is the loser.
     * @param withdrawn Whether the player has withdrawn the prize or the original deposit.
     */
    struct Player {
        address addr;
        bool isLoser;
        bool withdrawn;
    }

    /**
     * @notice A round of Poke The Bear.
     * @param status The status of the round.
     * @param cutoffTime The cutoff time to start or cancel the round if there aren't enough players.
     * @param drawnAt The timestamp when the round was drawn.
     * @param commitment The commitment of the shuffled player indices.
     * @param salt The salt used to generate the commitment.
     * @param playerIndices The player indices.
     * @param players The players.
     */
    struct Round {
        RoundStatus status;
        uint40 cutoffTime;
        uint40 drawnAt;
        bytes32 commitment;
        bytes32 salt;
        uint8[32] playerIndices;
        Player[] players;
    }

    /**
     * @param exists Whether the request exists.
     * @param caveId The id of the cave.
     * @param roundId The id of the round.
     * @param randomWord The random words returned by Chainlink VRF.
     *                   If randomWord == 0, then the request is still pending.
     */
    struct RandomnessRequest {
        bool exists;
        uint40 caveId;
        uint40 roundId;
        uint256 randomWord;
    }

    /**
     * @notice A cave of Poke The Bear.
     * @param enterAmount The amount to enter the cave with.
     * @param enterCurrency The currency to enter the cave with.
     * @param roundsCount The number of rounds in the cave.
     * @param lastCommittedRoundId The last committed round ID.
     * @param roundDuration The duration of a round.
     * @param playersPerRound The maximum number of players in a round.
     * @param protocolFeeBp The protocol fee in basis points.
     */
    struct Cave {
        uint256 enterAmount;
        address enterCurrency;
        uint40 roundsCount;
        uint40 lastCommittedRoundId;
        uint40 roundDuration;
        uint8 playersPerRound;
        uint16 protocolFeeBp;
        bool isActive;
    }

    /**
     * @notice The calldata for commitments.
     * @param caveId The cave ID of the commitments.
     * @param commitments The commitments. The pre-image of the commitment is the shuffled player indices.
     */
    struct CommitmentCalldata {
        uint256 caveId;
        bytes32[] commitments;
    }

    /**
     * @notice The calldata for a withdrawal/claim/rollover.
     * @param caveId The cave ID of the withdrawal/claim/rollover.
     * @param playerDetails The player's details in the rounds' players array.
     */
    struct WithdrawalCalldata {
        uint256 caveId;
        PlayerWithdrawalCalldata[] playerDetails;
    }

    /**
     * @notice The calldata for a withdrawal/claim/rollover.
     * @param caveId The cave ID of the withdrawal/claim/rollover.
     * @param startingRoundId The starting round ID to enter.
     * @param numberOfExtraRoundsToEnter The number of extra rounds to enter, in addition to rollover rounds.
     * @param playerDetails The player's details in the rounds' players array.
     */
    struct RolloverCalldata {
        uint256 caveId;
        uint256 startingRoundId;
        uint256 numberOfExtraRoundsToEnter;
        PlayerWithdrawalCalldata[] playerDetails;
    }

    /**
     * @notice The calldata for a single player withdrawal/claim/rollover.
     * @param roundId The round ID of the withdrawal/claim/rollover.
     * @param playerIndex The player index of the withdrawal/claim/rollover.
     */
    struct PlayerWithdrawalCalldata {
        uint256 roundId;
        uint256 playerIndex;
    }

    /**
     * @notice The withdrawal/claim/rollover.
     * @param caveId The cave ID of the withdrawal/claim/rollover.
     * @param roundIds The round IDs to withdraw/claim/rollover.
     */
    struct Withdrawal {
        uint256 caveId;
        uint256[] roundIds;
    }

    /**
     * @notice The rollover for event emission.
     * @param caveId The cave ID of the rollover.
     * @param rolledOverRoundIds The rolled over round IDs.
     * @param rollingOverToRoundIdStart The starting round ID to roll into
     */
    struct Rollover {
        uint256 caveId;
        uint256[] rolledOverRoundIds;
        uint256 rollingOverToRoundIdStart;
    }

    /**
     * @notice This is used to accumulate the amount of tokens to be transferred.
     * @param tokenAddress The address of the token.
     * @param amount The amount of tokens accumulated.
     */
    struct TransferAccumulator {
        address tokenAddress;
        uint256 amount;
    }

    event CommitmentsSubmitted(CommitmentCalldata[] commitments);
    event DepositsRolledOver(Rollover[] rollovers, address player);
    event DepositsRefunded(Withdrawal[] deposits, address player);
    event PrizesClaimed(Withdrawal[] prizes, address player);
    event ProtocolFeeRecipientUpdated(address protocolFeeRecipient);
    event RoundStatusUpdated(uint256 caveId, uint256 roundId, RoundStatus status);
    event RoundsCancelled(uint256 caveId, uint256 startingRoundId, uint256 numberOfRounds);
    event RoundsEntered(uint256 caveId, uint256 startingRoundId, uint256 numberOfRounds, address player);
    event RandomnessRequested(uint256 caveId, uint256 roundId, uint256 requestId);
    event CaveAdded(
        uint256 caveId,
        uint256 enterAmount,
        address enterCurrency,
        uint40 roundDuration,
        uint8 playersPerRound,
        uint16 protocolFeeBp
    );
    event CaveRemoved(uint256 caveId);

    error CommitmentNotAvailable();
    error ExceedsMaximumNumberOfPlayersPerRound();
    error HashedPlayerIndicesDoesNotMatchCommitment();
    error InactiveCave();
    error IndivisibleEnterAmount();
    error IneligibleToWithdraw(uint256 caveId, uint256 roundId);
    error InvalidEnterAmount();
    error InsufficientNumberOfPlayers();
    error InvalidCommitment(uint256 caveId, uint256 roundId);
    error InvalidPlayerDetails();
    error InvalidPlayerIndex(uint256 caveId, uint256 roundId);
    error InvalidRoundDuration();
    error InvalidRoundParameters();
    error InvalidRoundStatus();
    error InvalidEnterCurrency();
    error InvalidValue();
    error NotOperator();
    error NotOwner();
    error NotCancellable();
    error PlayerAlreadyParticipated(uint256 caveId, uint256 roundId, address player);
    error ProtocolFeeBasisPointsTooHigh();
    error RepeatingPlayerIndex();
    error RandomnessRequestAlreadyExists();
    error RoundCannotBeEntered(uint256 caveId, uint256 roundId);
    error RoundsIncomplete();

    /**
     * @notice Add a new cave. Only callable by the contract owner.
     * @param enterAmount The amount to enter the cave with.
     * @param enterCurrency The currency to enter the cave with.
     * @param playersPerRound The maximum number of players in a round.
     * @param roundDuration The duration of a round.
     * @param protocolFeeBp The protocol fee in basis points. Max 25%.
     */
    function addCave(
        uint256 enterAmount,
        address enterCurrency,
        uint8 playersPerRound,
        uint40 roundDuration,
        uint16 protocolFeeBp
    ) external returns (uint256 caveId);

    /**
     * @notice Remove a cave. Only callable by the contract owner.
     * @param caveId The cave ID to remove.
     */
    function removeCave(uint256 caveId) external;

    /**
     * @dev Update the protocol fee recipient. Only callable by the contract owner.
     * @param _protocolFeeRecipient The address of the protocol fee recipient
     */
    function updateProtocolFeeRecipient(address _protocolFeeRecipient) external;

    /**
     * @notice Enter the current round of a cave.
     * @param caveId The cave ID of the round to enter.
     * @param startingRoundId The starting round ID to enter.
     * @param numberOfRounds The number of rounds to enter, starting from the starting round ID.
     */
    function enter(uint256 caveId, uint256 startingRoundId, uint256 numberOfRounds) external payable;

    /**
     * @notice Commit the player indices for multiple rounds.
     * @param commitments The array of commitments.
     */
    function commit(CommitmentCalldata[] calldata commitments) external;

    /**
     * @notice Reveal the result of a round.
     * @param requestId The Chainlink VRF request ID.
     * @param playerIndices The indices of the players.
     * @param salt The salt used to concatenate with the playerIndices to generate the commitment.
     */
    function reveal(uint256 requestId, uint256 playerIndices, bytes32 salt) external;

    /**
     * @notice Get a refund for cancelled rounds.
     * @param refundCalldataArray The array of refund calldata.
     */
    function refund(WithdrawalCalldata[] calldata refundCalldataArray) external;

    /**
     * @notice Rollover cancelled rounds' deposits to the current round + upcoming rounds.
     * @param rolloverCalldataArray The array of rollover calldata.
     */
    function rollover(RolloverCalldata[] calldata rolloverCalldataArray) external payable;

    /**
     * @notice Claim prizes for multiple rounds.
     * @param claimPrizeCalldataArray The array of claim prize calldata.
     */
    function claimPrizes(WithdrawalCalldata[] calldata claimPrizeCalldataArray) external;

    /**
     * @notice Cancel the latest round when the round is expired.
     * @param caveId The cave ID of the round to cancel.
     */
    function cancel(uint256 caveId) external;

    /**
     * @notice Allow the contract owner to cancel the current and future rounds if the contract is paused.
     * @param caveId The cave ID of the rounds to cancel.
     * @param numberOfRounds The number of rounds to cancel..
     */
    function cancel(uint256 caveId, uint256 numberOfRounds) external;

    /**
     * @notice Get a round of a given cave.
     * @param caveId The cave ID.
     * @param roundId The round ID.
     */
    function getRound(
        uint256 caveId,
        uint256 roundId
    )
        external
        view
        returns (
            RoundStatus status,
            uint40 cutoffTime,
            uint40 drawnAt,
            bytes32 commitment,
            bytes32 salt,
            uint8[32] memory playerIndices,
            Player[] memory players
        );

    /**
     * @notice Check if the player is in a specific round.
     * @param caveId The cave ID.
     * @param roundId The round ID.
     * @return The player's address.
     */
    function isPlayerInRound(uint256 caveId, uint256 roundId, address player) external view returns (bool);

    /**
     * @notice This function allows the owner to pause/unpause the contract.
     */
    function togglePaused() external;
}

File 11 of 20 : IWETH.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0;

interface IWETH {
    function deposit() external payable;

    function transfer(address dst, uint256 wad) external returns (bool);

    function withdraw(uint256 wad) external;
}

File 12 of 20 : IERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

interface IERC20 {
    event Transfer(address indexed from, address indexed to, uint256 value);

    event Approval(address indexed owner, address indexed spender, uint256 value);

    function totalSupply() external view returns (uint256);

    function balanceOf(address account) external view returns (uint256);

    function transfer(address to, uint256 amount) external returns (bool);

    function allowance(address owner, address spender) external view returns (uint256);

    function approve(address spender, uint256 amount) external returns (bool);

    function transferFrom(address from, address to, uint256 amount) external returns (bool);

    function decimals() external view returns (uint8);
}

File 13 of 20 : LowLevelErrors.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

/**
 * @notice It is emitted if the ETH transfer fails.
 */
error ETHTransferFail();

/**
 * @notice It is emitted if the ERC20 approval fails.
 */
error ERC20ApprovalFail();

/**
 * @notice It is emitted if the ERC20 transfer fails.
 */
error ERC20TransferFail();

/**
 * @notice It is emitted if the ERC20 transferFrom fails.
 */
error ERC20TransferFromFail();

/**
 * @notice It is emitted if the ERC721 transferFrom fails.
 */
error ERC721TransferFromFail();

/**
 * @notice It is emitted if the ERC1155 safeTransferFrom fails.
 */
error ERC1155SafeTransferFromFail();

/**
 * @notice It is emitted if the ERC1155 safeBatchTransferFrom fails.
 */
error ERC1155SafeBatchTransferFromFail();

File 14 of 20 : GenericErrors.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

/**
 * @notice It is emitted if the call recipient is not a contract.
 */
error NotAContract();

File 15 of 20 : IReentrancyGuard.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

/**
 * @title IReentrancyGuard
 * @author LooksRare protocol team (👀,💎)
 */
interface IReentrancyGuard {
    /**
     * @notice This is returned when there is a reentrant call.
     */
    error ReentrancyFail();
}

File 16 of 20 : TokenType.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

enum TokenType {
    ERC20,
    ERC721,
    ERC1155
}

File 17 of 20 : IAccessControl.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)

pragma solidity ^0.8.20;

/**
 * @dev External interface of AccessControl declared to support ERC165 detection.
 */
interface IAccessControl {
    /**
     * @dev The `account` is missing a role.
     */
    error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);

    /**
     * @dev The caller of a function is not the expected one.
     *
     * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
     */
    error AccessControlBadConfirmation();

    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {AccessControl-_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `callerConfirmation`.
     */
    function renounceRole(bytes32 role, address callerConfirmation) external;
}

File 18 of 20 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (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;
    }
}

File 19 of 20 : ERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)

pragma solidity ^0.8.20;

import {IERC165} from "./IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

File 20 of 20 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

Settings
{
  "remappings": [
    "@chainlink/=node_modules/@chainlink/",
    "@ensdomains/=node_modules/@ensdomains/",
    "@eth-optimism/=node_modules/@eth-optimism/",
    "@looksrare/=node_modules/@looksrare/",
    "@openzeppelin/=node_modules/@openzeppelin/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "eth-gas-reporter/=node_modules/eth-gas-reporter/",
    "forge-std/=lib/forge-std/src/",
    "hardhat/=node_modules/hardhat/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 888888
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "london",
  "viaIR": true,
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_operator","type":"address"},{"internalType":"address","name":"_protocolFeeRecipient","type":"address"},{"internalType":"address","name":"wrappedNativeToken","type":"address"},{"internalType":"address","name":"_transferManager","type":"address"},{"internalType":"bytes32","name":"keyHash","type":"bytes32"},{"internalType":"address","name":"vrfCoordinator","type":"address"},{"internalType":"uint64","name":"subscriptionId","type":"uint64"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[],"name":"CommitmentNotAvailable","type":"error"},{"inputs":[],"name":"ERC20TransferFail","type":"error"},{"inputs":[],"name":"ExceedsMaximumNumberOfPlayersPerRound","type":"error"},{"inputs":[],"name":"HashedPlayerIndicesDoesNotMatchCommitment","type":"error"},{"inputs":[],"name":"InactiveCave","type":"error"},{"inputs":[],"name":"IndivisibleEnterAmount","type":"error"},{"inputs":[{"internalType":"uint256","name":"caveId","type":"uint256"},{"internalType":"uint256","name":"roundId","type":"uint256"}],"name":"IneligibleToWithdraw","type":"error"},{"inputs":[],"name":"InsufficientNumberOfPlayers","type":"error"},{"inputs":[{"internalType":"uint256","name":"caveId","type":"uint256"},{"internalType":"uint256","name":"roundId","type":"uint256"}],"name":"InvalidCommitment","type":"error"},{"inputs":[],"name":"InvalidEnterAmount","type":"error"},{"inputs":[],"name":"InvalidEnterCurrency","type":"error"},{"inputs":[],"name":"InvalidPlayerDetails","type":"error"},{"inputs":[{"internalType":"uint256","name":"caveId","type":"uint256"},{"internalType":"uint256","name":"roundId","type":"uint256"}],"name":"InvalidPlayerIndex","type":"error"},{"inputs":[],"name":"InvalidRoundDuration","type":"error"},{"inputs":[],"name":"InvalidRoundParameters","type":"error"},{"inputs":[],"name":"InvalidRoundStatus","type":"error"},{"inputs":[],"name":"InvalidValue","type":"error"},{"inputs":[],"name":"IsPaused","type":"error"},{"inputs":[],"name":"NotAContract","type":"error"},{"inputs":[],"name":"NotCancellable","type":"error"},{"inputs":[],"name":"NotOperator","type":"error"},{"inputs":[],"name":"NotOwner","type":"error"},{"inputs":[],"name":"NotPaused","type":"error"},{"inputs":[{"internalType":"address","name":"have","type":"address"},{"internalType":"address","name":"want","type":"address"}],"name":"OnlyCoordinatorCanFulfill","type":"error"},{"inputs":[{"internalType":"uint256","name":"caveId","type":"uint256"},{"internalType":"uint256","name":"roundId","type":"uint256"},{"internalType":"address","name":"player","type":"address"}],"name":"PlayerAlreadyParticipated","type":"error"},{"inputs":[],"name":"ProtocolFeeBasisPointsTooHigh","type":"error"},{"inputs":[],"name":"RandomnessRequestAlreadyExists","type":"error"},{"inputs":[],"name":"ReentrancyFail","type":"error"},{"inputs":[],"name":"RepeatingPlayerIndex","type":"error"},{"inputs":[{"internalType":"uint256","name":"caveId","type":"uint256"},{"internalType":"uint256","name":"roundId","type":"uint256"}],"name":"RoundCannotBeEntered","type":"error"},{"inputs":[],"name":"RoundsIncomplete","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"caveId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"enterAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"enterCurrency","type":"address"},{"indexed":false,"internalType":"uint40","name":"roundDuration","type":"uint40"},{"indexed":false,"internalType":"uint8","name":"playersPerRound","type":"uint8"},{"indexed":false,"internalType":"uint16","name":"protocolFeeBp","type":"uint16"}],"name":"CaveAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"caveId","type":"uint256"}],"name":"CaveRemoved","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint256","name":"caveId","type":"uint256"},{"internalType":"bytes32[]","name":"commitments","type":"bytes32[]"}],"indexed":false,"internalType":"struct IPokeTheBear.CommitmentCalldata[]","name":"commitments","type":"tuple[]"}],"name":"CommitmentsSubmitted","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint256","name":"caveId","type":"uint256"},{"internalType":"uint256[]","name":"roundIds","type":"uint256[]"}],"indexed":false,"internalType":"struct IPokeTheBear.Withdrawal[]","name":"deposits","type":"tuple[]"},{"indexed":false,"internalType":"address","name":"player","type":"address"}],"name":"DepositsRefunded","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint256","name":"caveId","type":"uint256"},{"internalType":"uint256[]","name":"rolledOverRoundIds","type":"uint256[]"},{"internalType":"uint256","name":"rollingOverToRoundIdStart","type":"uint256"}],"indexed":false,"internalType":"struct IPokeTheBear.Rollover[]","name":"rollovers","type":"tuple[]"},{"indexed":false,"internalType":"address","name":"player","type":"address"}],"name":"DepositsRolledOver","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint256","name":"caveId","type":"uint256"},{"internalType":"uint256[]","name":"roundIds","type":"uint256[]"}],"indexed":false,"internalType":"struct IPokeTheBear.Withdrawal[]","name":"prizes","type":"tuple[]"},{"indexed":false,"internalType":"address","name":"player","type":"address"}],"name":"PrizesClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"protocolFeeRecipient","type":"address"}],"name":"ProtocolFeeRecipientUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"caveId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"roundId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"requestId","type":"uint256"}],"name":"RandomnessRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"caveId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"roundId","type":"uint256"},{"indexed":false,"internalType":"enum IPokeTheBear.RoundStatus","name":"status","type":"uint8"}],"name":"RoundStatusUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"caveId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startingRoundId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"numberOfRounds","type":"uint256"}],"name":"RoundsCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"caveId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startingRoundId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"numberOfRounds","type":"uint256"},{"indexed":false,"internalType":"address","name":"player","type":"address"}],"name":"RoundsEntered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"enterAmount","type":"uint256"},{"internalType":"address","name":"enterCurrency","type":"address"},{"internalType":"uint8","name":"playersPerRound","type":"uint8"},{"internalType":"uint40","name":"roundDuration","type":"uint40"},{"internalType":"uint16","name":"protocolFeeBp","type":"uint16"}],"name":"addCave","outputs":[{"internalType":"uint256","name":"caveId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"caveId","type":"uint256"},{"internalType":"uint256","name":"numberOfRounds","type":"uint256"}],"name":"cancel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"caveId","type":"uint256"}],"name":"cancel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"caveId","type":"uint256"},{"internalType":"uint256","name":"roundId","type":"uint256"}],"name":"cancellable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"caveId","type":"uint256"}],"name":"caves","outputs":[{"internalType":"uint256","name":"enterAmount","type":"uint256"},{"internalType":"address","name":"enterCurrency","type":"address"},{"internalType":"uint40","name":"roundsCount","type":"uint40"},{"internalType":"uint40","name":"lastCommittedRoundId","type":"uint40"},{"internalType":"uint40","name":"roundDuration","type":"uint40"},{"internalType":"uint8","name":"playersPerRound","type":"uint8"},{"internalType":"uint16","name":"protocolFeeBp","type":"uint16"},{"internalType":"bool","name":"isActive","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"caveId","type":"uint256"},{"components":[{"internalType":"uint256","name":"roundId","type":"uint256"},{"internalType":"uint256","name":"playerIndex","type":"uint256"}],"internalType":"struct IPokeTheBear.PlayerWithdrawalCalldata[]","name":"playerDetails","type":"tuple[]"}],"internalType":"struct IPokeTheBear.WithdrawalCalldata[]","name":"claimPrizeCalldataArray","type":"tuple[]"}],"name":"claimPrizes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"caveId","type":"uint256"},{"internalType":"bytes32[]","name":"commitments","type":"bytes32[]"}],"internalType":"struct IPokeTheBear.CommitmentCalldata[]","name":"commitments","type":"tuple[]"}],"name":"commit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"caveId","type":"uint256"},{"internalType":"uint256","name":"startingRoundId","type":"uint256"},{"internalType":"uint256","name":"numberOfRounds","type":"uint256"}],"name":"enter","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"caveId","type":"uint256"},{"internalType":"uint256","name":"roundId","type":"uint256"}],"name":"getRound","outputs":[{"internalType":"enum IPokeTheBear.RoundStatus","name":"status","type":"uint8"},{"internalType":"uint40","name":"cutoffTime","type":"uint40"},{"internalType":"uint40","name":"drawnAt","type":"uint40"},{"internalType":"bytes32","name":"commitment","type":"bytes32"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint8[32]","name":"playerIndices","type":"uint8[32]"},{"components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"bool","name":"isLoser","type":"bool"},{"internalType":"bool","name":"withdrawn","type":"bool"}],"internalType":"struct IPokeTheBear.Player[]","name":"players","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"caveId","type":"uint256"},{"internalType":"uint256","name":"roundId","type":"uint256"},{"internalType":"address","name":"player","type":"address"}],"name":"isPlayerInRound","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextCaveId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"requestId","type":"uint256"}],"name":"randomnessRequests","outputs":[{"internalType":"bool","name":"exists","type":"bool"},{"internalType":"uint40","name":"caveId","type":"uint40"},{"internalType":"uint40","name":"roundId","type":"uint40"},{"internalType":"uint256","name":"randomWord","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"requestId","type":"uint256"},{"internalType":"uint256[]","name":"randomWords","type":"uint256[]"}],"name":"rawFulfillRandomWords","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"caveId","type":"uint256"},{"components":[{"internalType":"uint256","name":"roundId","type":"uint256"},{"internalType":"uint256","name":"playerIndex","type":"uint256"}],"internalType":"struct IPokeTheBear.PlayerWithdrawalCalldata[]","name":"playerDetails","type":"tuple[]"}],"internalType":"struct IPokeTheBear.WithdrawalCalldata[]","name":"refundCalldataArray","type":"tuple[]"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"caveId","type":"uint256"}],"name":"removeCave","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"requestId","type":"uint256"},{"internalType":"uint256","name":"playerIndices","type":"uint256"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"reveal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"caveId","type":"uint256"},{"internalType":"uint256","name":"startingRoundId","type":"uint256"},{"internalType":"uint256","name":"numberOfExtraRoundsToEnter","type":"uint256"},{"components":[{"internalType":"uint256","name":"roundId","type":"uint256"},{"internalType":"uint256","name":"playerIndex","type":"uint256"}],"internalType":"struct IPokeTheBear.PlayerWithdrawalCalldata[]","name":"playerDetails","type":"tuple[]"}],"internalType":"struct IPokeTheBear.RolloverCalldata[]","name":"rolloverCalldataArray","type":"tuple[]"}],"name":"rollover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"togglePaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_protocolFeeRecipient","type":"address"}],"name":"updateProtocolFeeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"}]

61014034620001bb576001600160401b036200508238819003601f8101601f1916840183811185821017620001c05784928291604052833961010093849181010312620001bb576200005181620001d6565b916200006060208301620001d6565b906200006f60408401620001d6565b916200007e60608501620001d6565b6200008c60808601620001d6565b9560a08601519260e0620000a360c08901620001d6565b9701519485168503620001bb57620000d5620000dc928a61ff00196001541617600155886080526001600755620001eb565b506200026b565b5060a05260c0526001600160a01b03928316855260e05291811661012090815291168015620001a957600680546001600160a01b031916821790556040519081527fc1b5345cce283376356748dc57f2dfa7120431d016fc7ca9ba641bc65f91411d90602090a160405190614d5492836200030e843960805183614743015260a051836142d4015260c0518381816139c50152613ccb015260e0518381816139eb0152613cf1015251828181613a3b0152613d40015251818181611b5b01528181611eb301526120be0152f35b604051632a9ffab760e21b8152600490fd5b600080fd5b634e487b7160e01b600052604160045260246000fd5b51906001600160a01b0382168203620001bb57565b6001600160a01b031660008181527fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5602052604081205490919060ff166200026757818052816020526040822081835260205260408220600160ff198254161790553391600080516020620050628339815191528180a4600190565b5090565b6001600160a01b031660008181527fee57cd81e84075558e8fcc182a1f4393f91fc97f963a136e66b7f949a62f319f60205260408120549091907f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b9299060ff166200030857808352826020526040832082845260205260408320600160ff1982541617905560008051602062005062833981519152339380a4600190565b50509056fe6080604052600436101561001257600080fd5b60003560e01c8062efa895146101d657806301ffc9a7146101d15780631df47f80146101cc5780631fe543e3146101c7578063248a9ca3146101c2578063286eca7f146101bd5780632f2ff15d146101b857806331c58858146101b357806336566f06146101ae57806336568abe146101a957806339ec68a3146101a45780633ca6915f1461019f57806340e58ee51461019a57806344ce2671146101955780635c975abb146101905780635cb6dfff1461018b57806361d49ea81461018657806364df049e146101815780636be5361e1461017c57806378c3a5dd1461017757806391d1485414610172578063962626e81461016d578063a217fddf14610168578063bc20805714610163578063d547741f1461015e578063d7eb82a714610159578063fad8269f146101545763faf7d65e1461014f57600080fd5b6124bb565b612264565b6121fa565b61219d565b611fc8565b611f8e565b611a48565b6119ca565b6118ff565b61166d565b61161b565b61126f565b6111f9565b6111b8565b611143565b611021565b610e2b565b610c5b565b610abc565b6109bf565b610983565b61091b565b610813565b6107c6565b61071c565b61051c565b61043a565b346104355760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104355760043560243590600190600260ff835460081c161461040b5761024f6102007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff6001541617600155565b610257614904565b61025f614666565b81610274826000526005602052604060002090565b01805464ffffffffff90818160a01c16946102976102928888612a59565b612a76565b918388159182156103fc575b50506103d257855b8281111561037557505082547fffffffffffffff0000000000ffffffffffffffffffffffffffffffffffffffff16911660a01b78ffffffffff0000000000000000000000000000000000000000161790557fddd9a1ac1ae0095c1389781239f4f4280ebfb649201b0556f78e77fa289e91839261033f90604051938493846040919493926060820195825260208201520152565b0390a16103736101007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff6001541617600155565b005b806103cc6103a184936103928a6000526003602052604060002090565b90600052602052604060002090565b60057fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b016102ab565b60046040517f67909b15000000000000000000000000000000000000000000000000000000008152fd5b60c81c168311905083386102a3565b60046040517f1bbee726000000000000000000000000000000000000000000000000000000008152fd5b600080fd5b346104355760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610435576004357fffffffff00000000000000000000000000000000000000000000000000000000811680910361043557807f7965db0b00000000000000000000000000000000000000000000000000000000602092149081156104cf575b506040519015158152f35b7f01ffc9a700000000000000000000000000000000000000000000000000000000915014386104c4565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361043557565b346104355760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104355760043573ffffffffffffffffffffffffffffffffffffffff811680910361043557610574614666565b80156105d1576020817fc1b5345cce283376356748dc57f2dfa7120431d016fc7ca9ba641bc65f91411d927fffffffffffffffffffffffff00000000000000000000000000000000000000006006541617600655604051908152a1005b60046040517faa7feadc000000000000000000000000000000000000000000000000000000008152fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60e0810190811067ffffffffffffffff82111761064657604052565b6105fb565b67ffffffffffffffff811161064657604052565b6040810190811067ffffffffffffffff82111761064657604052565b6060810190811067ffffffffffffffff82111761064657604052565b610400810190811067ffffffffffffffff82111761064657604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761064657604052565b604051906107028261067b565b565b67ffffffffffffffff81116106465760051b60200190565b346104355760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104355760243567ffffffffffffffff811161043557366023820112156104355780600401359061077782610704565b9061078560405192836106b4565b82825260209260248484019160051b8301019136831161043557602401905b8282106107b7576103738460043561472c565b813581529084019084016107a4565b346104355760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104355760043560005260006020526020600160406000200154604051908152f35b346104355760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104355760043561084d614666565b80600052600560205260016040600020015464ffffffffff808260c81c169160a01c16106108f1576108ec816108dc60026108b37f3b1b1a7c6b021e524cac489566ae6d22e8dde1b38bcc164bb70490fa21daf97c956000526005602052604060002090565b017fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff8154169055565b6040519081529081906020820190565b0390a1005b60046040517ff9250d0c000000000000000000000000000000000000000000000000000000008152fd5b346104355760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610435576103736004356109586104f9565b90806000526000602052610973600160406000200154614ae6565b614b60565b600091031261043557565b346104355760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610435576020600754604051908152f35b346104355760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610435576109f6614666565b60015460ff811615610a5f5750610a0b614904565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00600154166001557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6020604051338152a1005b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00600191610a8b6148ce565b16176001557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a1005b346104355760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261043557610af36104f9565b3373ffffffffffffffffffffffffffffffffffffffff821603610b1c5761037390600435614c43565b60046040517f6697b232000000000000000000000000000000000000000000000000000000008152fd5b60061115610b5057565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b906006821015610b505752565b9193959490946104c091610ba38484810198610b7f565b64ffffffffff806020971687860152604095168585015260609788850152608084015260a083016000905b868210610c42575050506104a08201528551938490526104e001948201936000915b848310610c005750505050505090565b8551805173ffffffffffffffffffffffffffffffffffffffff168852808501511515888601528101511515878201529581019594830194600190920191610bf0565b825160ff16815291860191600191909101908601610bce565b34610435576040807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610435576104008151610c9981610697565b369037600090600435825260036020528082206024358352602052808220815191610cc38361062a565b81549260ff84166006811015610d935790610d8f929181526020810193610d1464ffffffffff610cff818960081c16889064ffffffffff169052565b8484019760301c16879064ffffffffff169052565b60018101546060830190815260028201549060808401918252610d7c610d70610d526004610d446003880161302e565b9660a0890197885201613300565b9560c081019687525198610d658a610b46565b5164ffffffffff1690565b985164ffffffffff1690565b9051915192519351945197889788610b8c565b0390f35b6024867f4e487b710000000000000000000000000000000000000000000000000000000081526021600452fd5b9060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8301126104355760043567ffffffffffffffff9283821161043557806023830112156104355781600401359384116104355760248460051b83010111610435576024019190565b3461043557610e3936610dc0565b610e416146c9565b60005b818110610e7d57507f1f0def5d5179f4d53a0dafd78f3ae044c7cbf799630739fd50674bbec8c356b8916108ec60405192839283612ab0565b610e8881838561294f565b3590610e9e826000526005602052604060002090565b91610eb8610eb4600285015460ff9060401c1690565b1590565b610ff757600180930190610eea610ee0610edb845464ffffffffff9060c81c1690565b6129c3565b64ffffffffff1690565b610f02610ef885888a61294f565b60208101906129f7565b9260005b848110610f7857505050610ee0610292610f729493610f2493612a59565b7fffff0000000000ffffffffffffffffffffffffffffffffffffffffffffffffff7dffffffffff0000000000000000000000000000000000000000000000000083549260c81b169116179055565b01610e44565b610f828185612a59565b610f8d828786612a66565b35908115610fb9579089610fb1819493610392876000526003602052604060002090565b015501610f06565b6040517f795bfe85000000000000000000000000000000000000000000000000000000008152600481018590526024810191909152604490fd5b0390fd5b60046040517fe7d1a70d000000000000000000000000000000000000000000000000000000008152fd5b346104355760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261043557600435600260ff60015460081c161461040b576110946102007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff6001541617600155565b8060005260056020526040600020611105610eb464ffffffffff600184015460a01c169260036020526110dc8460406000209064ffffffffff16600052602052604060002090565b906110f960026110ed845460ff1690565b92015460281c60ff1690565b90600483015492614558565b6103d25761111291613e95565b6103736101007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff6001541617600155565b346104355760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104355761117a6104f9565b6044359060ff821682036104355760643564ffffffffff81168103610435576084359061ffff8216820361043557610d8f936108dc9360043561256d565b346104355760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261043557602060ff600154166040519015158152f35b346104355760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261043557600435600052600260205260806040600020600181549101546040519160ff81161515835264ffffffffff90818160081c16602085015260301c1660408301526060820152f35b346104355760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610435576024356044356112ac6148ce565b6004906112c482356000526002602052604060002090565b9081549264ffffffffff808560081c169460301c16916112f283610392876000526003602052604060002090565b906003611300835460ff1690565b61130981610b46565b036115f25760408051602081018981528183018490529194919061135881606081015b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018352826106b4565b5190209560019687850154036115ca578661138461137f848701938454938491015461255e565b612a4b565b90600386016000805b838110611499576103738d8d8d7ff7ab5a65307ab9788b10eab6a0e173842698dc9772bc3e58eaac1d6e0315b0598e6113f18f8f600282015560047fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b518481526020810183905260046040820152606090a161149261141e846000526005602052604060002090565b60065473ffffffffffffffffffffffffffffffffffffffff169061148c61148461145e8784015473ffffffffffffffffffffffffffffffffffffffff1690565b9261147e6114776002835493015461ffff9060301c1690565b61ffff1690565b90612c09565b612710900490565b916142ad565b0190614061565b6114ad8e6114a683612bf3565b1c60ff1690565b9160ff831690811580156115c1575b61157f578d821b908181166115575717928d929187916114f9906114e08589612c28565b90919060ff8084549260031b9316831b921b1916179055565b14611505575b0161138d565b6115526115128289612c41565b50740100000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff825416179055565b6114ff565b898d517f8ce0d24b000000000000000000000000000000000000000000000000000000008152fd5b8e89610ff38f8f519384937fa06986c7000000000000000000000000000000000000000000000000000000008552840160209093929193604081019481520152565b508582116114bc565b5083517fb06ec8f9000000000000000000000000000000000000000000000000000000008152fd5b826040517fc38434ab000000000000000000000000000000000000000000000000000000008152fd5b346104355760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261043557602073ffffffffffffffffffffffffffffffffffffffff60065416604051908152f35b346104355761167b36610dc0565b906001600260ff825460081c161461040b576116be6102007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff6001541617600155565b6116c66148ce565b6116ce612c59565b916116d884612c72565b9360005b818110611752577f151b7b4fba4f2f307fc85d2e1759f3691da9606509751f0f40fccf193e418e4d61033f8787602081015180611724575b5050604051918291339083612df8565b61174561174b925173ffffffffffffffffffffffffffffffffffffffff1690565b336142ad565b8380611714565b80856117608693858761294f565b82813591611778836000526005602052604060002090565b928b61178e855461178887614612565b90612a59565b926117a96117a160209283810190612cf0565b969093612d51565b51838152816117b787612d65565b910190815260005b868110611806575050505050856117de6118009594936117fa93612c09565b92015473ffffffffffffffffffffffffffffffffffffffff1690565b906143ef565b016116dc565b839597999a508681939597995061181d9294612db4565b80359061183882610392896000526003602052604060002090565b90611844825460ff1690565b9061184e82610b46565b60048092036118d6578f9493926118b9928861186d9301359101612c41565b5061187981848b6144cb565b75010000000000000000000000000000000000000000007fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff825416179055565b6118c4828551612d51565b520193918b98979593918d97956117bf565b506040517fc38434ab000000000000000000000000000000000000000000000000000000008152fd5b346104355760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104355760043560009081526005602090815260409182902080546001820154600290920154845191825273ffffffffffffffffffffffffffffffffffffffff83169382019390935264ffffffffff60a083811c82168387015260c89390931c811660608301528316608082015260ff602884901c81169282019290925261ffff603084901c1660c08201529190921c909116151560e082015261010090f35b346104355760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261043557602060ff611a3c611a086104f9565b6004356000526000845260406000209073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b54166040519015158152f35b611a5136610dc0565b600260ff60015460081c161461040b57611a926102007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff6001541617600155565b611a9a6148ce565b611aa2612c59565b611aaa612c59565b91611ab481612ea7565b93349160005b818110611c8657505050611c5c57602081015180611b3e575b50507f1e473be843779c10566d945a4adf38c5fa2f3585a52fc906f1d9e502cf3798879181602061033f93015180611b16575b5050604051918291339083612f6b565b611745611b37925173ffffffffffffffffffffffffffffffffffffffff1690565b3880611b06565b611b9673ffffffffffffffffffffffffffffffffffffffff9492947f000000000000000000000000000000000000000000000000000000000000000016945173ffffffffffffffffffffffffffffffffffffffff1690565b90843b15610435576040517fda3e8ce400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9290921660048301523360248301523060448301526064820152926000908490608490829084905af1918215611c57577f1e473be843779c10566d945a4adf38c5fa2f3585a52fc906f1d9e502cf3798879361033f93611c3e575b5091819350611ad3565b80611c4b611c519261064b565b80610978565b38611c34565b612c1c565b60046040517f87b71f66000000000000000000000000000000000000000000000000000000008152fd5b611c91818385612f2b565b611c9e6060820182612cf0565b80915015611f6457611cbb82356000526005602052604060002090565b91611cdd600184015473ffffffffffffffffffffffffffffffffffffffff1690565b916040820135611ded575b91849392611cf88b93968d612d51565b5186358152611d0682612d65565b6020820152600094855b838110611d62575050956040611d3b611d429360019960208501359384910152604084013590612a59565b91356134df565b82611d51575b50505001611aba565b611d5a926143ef565b388781611d48565b909192939596979450611d8281611d7c6060880188612cf0565b90612db4565b6004611da1611d99600286015460ff9060281c1690565b8835846141b2565b611daa81610b46565b14611dd3575b9060019135611dc3826020870151612d51565b5201908c94979695939291611d10565b9690611de460019261178885614612565b97909150611db0565b9673ffffffffffffffffffffffffffffffffffffffff8381169081611e2d575050611e2790611e2160408401358654612c09565b90612aa3565b96611ce8565b8a5192999273ffffffffffffffffffffffffffffffffffffffff169181831603611e78575050611e6260408301358554612c09565b611e7160208b01918251612a59565b9052611ce8565b60208b019182519182611eb1575b50505073ffffffffffffffffffffffffffffffffffffffff84168a52611e7160408401358654612c09565b7f00000000000000000000000000000000000000000000000000000000000000001691823b15610435576040517fda3e8ce400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9290921660048301523360248301523060448301526064820152906000908290608490829084905af18015611c5757611f51575b8080611e86565b80611c4b611f5e9261064b565b38611f4a565b60046040517fc7017d52000000000000000000000000000000000000000000000000000000008152fd5b346104355760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261043557602060405160008152f35b60607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261043557600435604435600260ff60015460081c161461040b576120396102007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff6001541617600155565b6120416148ce565b612055826000526005602052604060002090565b6120818261207a600184015473ffffffffffffffffffffffffffffffffffffffff1690565b9254612c09565b9073ffffffffffffffffffffffffffffffffffffffff8082166120b45750503403611c5c57611112915b602435906134df565b93919334612173577f00000000000000000000000000000000000000000000000000000000000000001693843b15610435576040517fda3e8ce400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9290921660048301523360248301523060448301526064820152926000908490608490829084905af1928315611c575761111293612160575b506120ab565b80611c4b61216d9261064b565b3861215a565b60046040517fe2a8f8a0000000000000000000000000000000000000000000000000000000008152fd5b346104355760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610435576103736004356121da6104f9565b908060005260006020526121f5600160406000200154614ae6565b614c43565b346104355760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104355760443573ffffffffffffffffffffffffffffffffffffffff811681036104355761225a6020916024356004356133a6565b6040519015158152f35b346104355761227236610dc0565b6001600260ff825460081c161461040b576122b46102007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff6001541617600155565b6122bc6148ce565b6122c4612c59565b926122ce83612c72565b9260005b818110612319577fd53f2bb6fed83c8a1662fd984e0882cef7bc2c6dd8d4d8d482ca931945efd61961033f8688602081015180611724575050604051918291339083612df8565b80866123278693858761294f565b8781359161233f836000526005602052604060002090565b9260208083019161235c886123548587612cf0565b979050612d51565b51918183528061236b87612d65565b930192835260005b86811061239a57505050505050906117fa856117de61239495948454612c09565b016122d2565b8597999a5084969850611d7c8193956123b4939597612cf0565b8035906123cf82610392876000526003602052604060002090565b906123db825460ff1690565b908b8660049283860194855496816123f38993610b46565b86811061247f575b5050500135938410159050612444575061241b8f94939261242792612c41565b506118798184896144cb565b612432828751612d51565b5201918b98979593918e979593612373565b604080517fa06986c7000000000000000000000000000000000000000000000000000000008152918201888152602081018690528291010390fd5b6124a0945061249a6002610eb49597015460ff9060281c1690565b91614558565b6118d65786906124b0868a613e95565b908d918538806123fb565b346104355760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261043557602061225a60043560009080825260038452604082206024358352845260ff6002604080852094838654169481526005885220015460281c1690600483015492614558565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b8115612568570690565b61252f565b90919493929461257b614666565b60ff8116600281106128f6576020106128cc5761ffff84166109c481116128a2576125d49061271060ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85011691850204840361255e565b6128785764ffffffffff8616603c811090811561286c575b50612842577f44ab42484886e3b9dfa09fe03c00b19e3386faaa7313d5de2b4bcd7d1453dd799361283d9160075497846126308a6000526005602052604060002090565b5561268c86600161264b8c6000526005602052604060002090565b019073ffffffffffffffffffffffffffffffffffffffff167fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055565b6126de8260026126a68c6000526005602052604060002090565b01907fffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffff65ff000000000083549260281b169116179055565b61272a8160026126f88c6000526005602052604060002090565b019064ffffffffff167fffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000825416179055565b61277e8360026127448c6000526005602052604060002090565b01907fffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffff67ffff00000000000083549260301b169116179055565b6127cb60026127978b6000526005602052604060002090565b01680100000000000000007fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff825416179055565b6127d489613f21565b6127e86127e360075460010190565b600755565b6040519586958a879464ffffffffff60a09573ffffffffffffffffffffffffffffffffffffffff61ffff9660ff959b9a9660c08b019c8b5260208b015216604089015216606087015216608085015216910152565b0390a1565b60046040517f06201c01000000000000000000000000000000000000000000000000000000008152fd5b610e10915011386125ec565b60046040517f490bbdd0000000000000000000000000000000000000000000000000000000008152fd5b60046040517f36d36c7c000000000000000000000000000000000000000000000000000000008152fd5b60046040517fbaa3711d000000000000000000000000000000000000000000000000000000008152fd5b60046040517fe8a119d4000000000000000000000000000000000000000000000000000000008152fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b919081101561298f5760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc181360301821215610435570190565b612920565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b90600164ffffffffff809316019182116129d957565b612994565b91909164ffffffffff808094169116019182116129d957565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610435570180359067ffffffffffffffff821161043557602001918160051b3603831361043557565b90600182018092116129d957565b919082018092116129d957565b919081101561298f5760051b0190565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82019182116129d957565b919082039182116129d957565b916020908082850183865252604091828501946005958484881b83010196866000935b868510612ae65750505050505050505090565b9091929394959697987fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc082820301855289357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc18436030181121561043557830180358252878101357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe182360301811215610435570187813591019167ffffffffffffffff82116104355781861b918236038413610435577f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff908c8b840152808d8401521161043557600192828a939284936060938483013701019b01950195019397969594929190612ad3565b908160031b91808304600814901517156129d957565b818102929181159184041417156129d957565b6040513d6000823e3d90fd5b919091602083101561298f57601f908360051c01921690565b805482101561298f5760005260206000200190600090565b60405190612c668261065f565b60006020838281520152565b90612c7c82610704565b6040612c8a815192836106b4565b8382527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0612cb88395610704565b0191600091825b848110612ccd575050505050565b6020908251612cdb8161065f565b85815282606081830152828601015201612cbf565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610435570180359067ffffffffffffffff821161043557602001918160061b3603831361043557565b80511561298f5760200190565b805182101561298f5760209160051b010190565b90612d6f82610704565b612d7c60405191826106b4565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0612daa8294610704565b0190602036910137565b919081101561298f5760061b0190565b90815180825260208080930193019160005b828110612de4575050505090565b835185529381019392810192600101612dd6565b909291926040808301908084528251809252606084019160608160051b860101916020809501936000915b86848410612e4e57505050505073ffffffffffffffffffffffffffffffffffffffff91509416910152565b80612e97877fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08c6001969798999a0301875285838b518051845201519181858201520190612dc4565b9701930193019194939290612e23565b90612eb182610704565b604090612ec0825191826106b4565b8381527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0612eee8295610704565b0191600091825b848110612f03575050505050565b6020908351612f118161067b565b858152826060818301528686830152828501015201612ef5565b919081101561298f5760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8181360301821215610435570190565b9192909260409384840194808552815180965260609586860191878260051b880101926020809501986000925b848410612fc85750505050506107029394955094019073ffffffffffffffffffffffffffffffffffffffff169052565b90919293948680827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08d600195030187528d5190815181528580613017858501518a878601528a850190612dc4565b9301519101529c0194019401929994939190612f98565b6040805160009390929190835b602080601f880110156132f0576104006020926132e46001936132d98954916132b26131176132628c613212896131c260ff9761307c838a8d1660ff169052565b61308f8184018a8d60081c1660ff169052565b6130a28584018a8d60101c1660ff169052565b888b6102006060956130bd878201858560181c1660ff169052565b6130d26080958585888501921c1660ff169052565b61317860a0976130eb898401878760281c1660ff169052565b61312860c09b6131048d8601898960301c1660ff169052565b60e09e8f8601898960381c1660ff169052565b87876101008701921c1660ff169052565b61313d6101208401878760481c1660ff169052565b6131526101408401878760501c1660ff169052565b6131676101608401878760581c1660ff169052565b85856101808501921c1660ff169052565b61318d6101a08201858560681c1660ff169052565b6131a26101c08201858560701c1660ff169052565b6131b76101e08201858560781c1660ff169052565b01921c1660ff169052565b6131d76102208c01888b60881c1660ff169052565b6131ec6102408c01888b60901c1660ff169052565b6132016102608c01888b60981c1660ff169052565b86896102808d01921c1660ff169052565b6132276102a08a01868960a81c1660ff169052565b61323c6102c08a01868960b01c1660ff169052565b6132516102e08a01868960b81c1660ff169052565b84876103008b01921c1660ff169052565b6132776103208801848760c81c1660ff169052565b61328c6103408801848760d01c1660ff169052565b6132a16103608801848760d81c1660ff169052565b82856103808901921c1660ff169052565b6132c76103a08601828560e81c1660ff169052565b6103c08501908360f01c1660ff169052565b60f81c6103e0830152565b0194019501949261303b565b5050929350505061070282610697565b90815461330c81610704565b9260409361331c855191826106b4565b828152809460208092019260005281600020906000935b85851061334257505050505050565b600184819284516133528161067b565b865473ffffffffffffffffffffffffffffffffffffffff8116825260ff90818160a01c1615158584015260a81c16151586820152815201930194019391613333565b6201000082101561298f570190600090565b73ffffffffffffffffffffffffffffffffffffffff60ff9316600052600460205260406000209060005260205260016133e68260081c6040600020613394565b93905492161b9160031b1c16151590565b8054680100000000000000008110156106465761341991600182018155612c41565b9190916134b05780518254602083015160409093015173ffffffffffffffffffffffffffffffffffffffff9092167fffffffffffffffffffff000000000000000000000000000000000000000000009091161791151560a01b74ff0000000000000000000000000000000000000000169190911790151560a81b75ff00000000000000000000000000000000000000000016179055565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b929190801580156138d2575b6138a857613503846000526005602052604060002090565b936002850194855460409660ff82891c161561387f576135238686612a59565b9161353e610ee060018096015464ffffffffff9060c81c1690565b917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff92838501116138565761358187610392886000526003602052604060002090565b9161358d835460ff1690565b9061359782610b46565b86821161381e5760281c60ff16936135ae82610b46565b81156137cb575b50875b85811061360f575050985194855250505050602081019190915260408101919091523360608201529091507f9a711314e8e01b50116aefb9d50edc1a6b06e39986010af70d18671666586d0e90806080810161283d565b61361a33828a6133a6565b61378c57808914801561376f57845b6004918282018a815401938985116137295750918f916136648c9695938b9560006136526106f5565b338152928160208501528301526133f7565b61366f33868f61444f565b61367d575b505050016135b8565b61368686610b46565b8486036136745764ffffffffff90816136a8825464ffffffffff9060081c1690565b16156136ce575b5050146136bf575b853880613674565b6136c9818a613c62565b6136b7565b6136ec613722926136e48a5464ffffffffff1690565b9042166129de565b7fffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000ff65ffffffffff0083549260081b169116179055565b38806136af565b9350505050610ff389928e519384937fca10b936000000000000000000000000000000000000000000000000000000008552840160209093929193604081019481520152565b613787826103928b6000526003602052604060002090565b613629565b8b517f190f2750000000000000000000000000000000000000000000000000000000008152600481018990526024810191909152336044820152606490fd5b868911156135b55788016138076137f0826103928b6000526003602052604060002090565b866137fc825460ff1690565b600483015492614558565b156135b557613817915087613e95565b84386135b5565b8b517fca10b93600000000000000000000000000000000000000000000000000000000815260048101899052602481018a9052604490fd5b60048a517f5ee0d7b4000000000000000000000000000000000000000000000000000000008152fd5b600488517fe7d1a70d000000000000000000000000000000000000000000000000000000008152fd5b60046040517f558947cf000000000000000000000000000000000000000000000000000000008152fd5b5081156134eb565b90816020910312610435575190565b61393e613913613903836000526003602052604060002090565b6001600052602052604060002090565b60027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b64ffffffffff61399d814216613961613903856000526003602052604060002090565b907fffffffffffffffffffffffffffffffffffffffffff0000000000ffffffffffff6affffffffff00000000000083549260301b169116179055565b6040517f5d3b1d300000000000000000000000000000000000000000000000000000000081527f000000000000000000000000000000000000000000000000000000000000000060048201527f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff166024820152600360448201526207a1206064820152600160848201529160208360a48160007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff165af1928315611c5757600093613c32575b50613aa0613a99846000526002602052604060002090565b5460ff1690565b613c08577f34e010a4ef37e7b53b3d02e76e84b745a250daa244a2768dabaf7c0c1947963e613be784613b8061283d95613b33613b087ff7ab5a65307ab9788b10eab6a0e173842698dc9772bc3e58eaac1d6e0315b059996000526002602052604060002090565b60017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b8516613b49836000526002602052604060002090565b907fffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000ff65ffffffffff0083549260081b169116179055565b613bc8613b97826000526002602052604060002090565b66010000000000007fffffffffffffffffffffffffffffffffffffffffff0000000000ffffffffffff825416179055565b6040805185815260016020820152908101919091529081906060820190565b0390a160408051918252600160208301526002908201529081906060820190565b60046040517ff9012132000000000000000000000000000000000000000000000000000000008152fd5b613c5491935060203d8111613c5b575b613c4c81836106b4565b8101906138da565b9138613a81565b503d613c42565b90613c7e61391382610392856000526003602052604060002090565b64ffffffffff91613ca383421661396184610392856000526003602052604060002090565b6040517f5d3b1d300000000000000000000000000000000000000000000000000000000081527f000000000000000000000000000000000000000000000000000000000000000060048201527f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff166024820152600360448201526207a12060648201526001608482015260208160a48160007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff165af1908115611c5757600091613e77575b50613d9e613a99826000526002602052604060002090565b613c0857613e5281613e337ff7ab5a65307ab9788b10eab6a0e173842698dc9772bc3e58eaac1d6e0315b05996613e03613b087f34e010a4ef37e7b53b3d02e76e84b745a250daa244a2768dabaf7c0c1947963e966000526002602052604060002090565b613e1d818716613b49856000526002602052604060002090565b8616613961836000526002602052604060002090565b6040519182918686846040919493926060820195825260208201520152565b0390a161283d6040519283928360409060029294936060820195825260208201520152565b613e8f915060203d8111613c5b57613c4c81836106b4565b38613d86565b600161070292826000526003602052604060002081600052602052613ee3604060002060057fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b7ff7ab5a65307ab9788b10eab6a0e173842698dc9772bc3e58eaac1d6e0315b059606060405185815283602082015260056040820152a10190614061565b80600052600360205260406000206001600052602052604060002090600482015491613f57826000526005602052604060002090565b6002810180549094919060281c60ff168203613f7a5750505061070291506138e9565b8293614016600161403493613fd67ff7ab5a65307ab9788b10eab6a0e173842698dc9772bc3e58eaac1d6e0315b059969760017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b01740100000000000000000000000000000000000000007fffffffffffffff0000000000ffffffffffffffffffffffffffffffffffffffff825416179055565b60408051918252600160208301819052908201529081906060820190565b0390a161403f575050565b6136ec614054610702935464ffffffffff1690565b64ffffffffff42166129de565b90816000526003602052604060002081600052602052604060002091600483015492614097826000526005602052604060002090565b9360028501906140b56140af835460ff9060281c1690565b60ff1690565b81036140c8575050506107029250613c62565b91937ff7ab5a65307ab9788b10eab6a0e173842698dc9772bc3e58eaac1d6e0315b059919361411c8660017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b600190960180547fffffffffffffff0000000000ffffffffffffffffffffffffffffffffffffffff1660a083901b78ffffffffff00000000000000000000000000000000000000001617905564ffffffffff956141916040519283928360409060019294936060820195825260208201520152565b0390a161419d57505050565b54610702926136ec9164ffffffffff166136e4565b90929192602082359201356141d1826000526003602052604060002090565b83600052602052604060002060ff815416956004820191825480926141f58a610b46565b8960048110614262575b50505050821015614225579161421c611879926107029594612c41565b509283916144cb565b50506040517fa06986c700000000000000000000000000000000000000000000000000000000815260048101919091526024810191909152604490fd5b61426b93614558565b156142835761427a8585613e95565b388181896141ff565b60046040517fc38434ab000000000000000000000000000000000000000000000000000000008152fd5b919073ffffffffffffffffffffffffffffffffffffffff81166142f8575090610702915a917f00000000000000000000000000000000000000000000000000000000000000006149b1565b803b156143c5576040517fa9059cbb000000000000000000000000000000000000000000000000000000006020820190815273ffffffffffffffffffffffffffffffffffffffff9094166024820152604481019290925260009283928390614363816064810161132c565b51925af161436f61493b565b901561439b57805180614380575050565b81602080610eb4936143959501019101614999565b61439b57565b60046040517ff1568f95000000000000000000000000000000000000000000000000000000008152fd5b60046040517f09ee12d5000000000000000000000000000000000000000000000000000000008152fd5b9173ffffffffffffffffffffffffffffffffffffffff80825116921682811460001461442a5750602091500180519182018092116129d95752565b90602081019283518061443e575b50505252565b61444891336142ad565b3880614438565b909173ffffffffffffffffffffffffffffffffffffffff16600052600460205260406000209060005260205261448c8160081c6040600020613394565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600160ff849594549360031b94161b82841c17831b921b1916179055565b90915460ff8160a01c16908115614549575b8115614528575b506144ed575050565b6040517f7f7f26da00000000000000000000000000000000000000000000000000000000815260048101919091526024810191909152604490fd5b73ffffffffffffffffffffffffffffffffffffffff163314159050386144e4565b905060ff8160a81c16906144dd565b929091925464ffffffffff91828260081c16946006851015610b5057600185149586614608575b866145fd575b50856145f0575b5050831561459b575b50505090565b600283149350909183156145da575b50826145bb575b5050388080614595565b90915060301c811662015180018181116129d9571642101538806145b1565b60039193506145e881610b46565b1491386145aa565b60ff16119350388061458c565b421015955038614585565b801515965061457f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60ff60028354930154926146546127109161ffff8660301c16830390612c09565b049260281c1601908115612568570490565b3360009081527fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5602052604090205460ff161561469f57565b60046040517f30cd7471000000000000000000000000000000000000000000000000000000008152fd5b3360009081527fee57cd81e84075558e8fcc182a1f4393f91fc97f963a136e66b7f949a62f319f602052604090205460ff161561470257565b60046040517f7c214f04000000000000000000000000000000000000000000000000000000008152fd5b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016803303614897575080600052600260205260406000205460ff811661478757505050565b64ffffffffff9060081c166147ba610ee06147ac846000526002602052604060002090565b5460301c64ffffffffff1690565b916147d383610392846000526003602052604060002090565b60026147e0825460ff1690565b6147e981610b46565b146147f6575b5050505050565b6148666148547ff7ab5a65307ab9788b10eab6a0e173842698dc9772bc3e58eaac1d6e0315b0599661484f60019460037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b612d44565b51926000526002602052604060002090565b015561488a6040519283928360409060039294936060820195825260208201520152565b0390a138808080806147ef565b604490604051907f1cf993f40000000000000000000000000000000000000000000000000000000082523360048301526024820152fd5b60ff600154166148da57565b60046040517f1309a563000000000000000000000000000000000000000000000000000000008152fd5b60ff600154161561491157565b60046040517f6cd60201000000000000000000000000000000000000000000000000000000008152fd5b3d15614994573d9067ffffffffffffffff8211610646576040519161498860207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601846106b4565b82523d6000602084013e565b606090565b90816020910312610435575180151581036104355790565b6149c682849395600080809781948294f11590565b6149d1575b50505050565b73ffffffffffffffffffffffffffffffffffffffff16803b15614ae257604051937fd0e30db0000000000000000000000000000000000000000000000000000000008552838560048186865af1938415611c5757614a8a95602095614acf575b506040518096819582947fa9059cbb000000000000000000000000000000000000000000000000000000008452600484016020909392919373ffffffffffffffffffffffffffffffffffffffff60408201951681520152565b03925af18015611c5757614aa1575b8080806149cb565b614ac19060203d8111614ac8575b614ab981836106b4565b810190614999565b5038614a99565b503d614aaf565b80611c4b614adc9261064b565b38614a31565b8280fd5b80600052600060205260ff614b1f3360406000209073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b541615614b295750565b604490604051907fe2517d3f0000000000000000000000000000000000000000000000000000000082523360048301526024820152fd5b6000908082528160205260ff614b9984604085209073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b5416614c3d5780825281602052614bd383604084209073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b60017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008254161790557f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d73ffffffffffffffffffffffffffffffffffffffff3394169280a4600190565b50905090565b6000908082528160205260ff614c7c84604085209073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b541615614c3d5780825281602052614cb783604084209073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0081541690557ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b73ffffffffffffffffffffffffffffffffffffffff3394169280a460019056fea2646970667358221220a125cb17f3508dc82892b7bcfc8e7235a8793e3b5b448661287891a1a590f48364736f6c634300081400332f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d000000000000000000000000b5a9e5a319c7fda551a30be592c77394bf935c6f000000000000000000000000842ca39dfd984d4349ce8d8c95577e2bf42f4db0000000000000000000000000c8c57e4c73c71f72ca0a7e043e5d2d144f98ef13000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000000000000000ea4af05656c17b90f4d64add29e1d8af398995b04c28e9951adb9721ef74c74f93e6a478f39e7e0777be13527e7ef000000000000000000000000271682deb8c4e0901d1a1550ad2e64d568e6990900000000000000000000000000000000000000000000000000000000000002de

Deployed Bytecode

0x6080604052600436101561001257600080fd5b60003560e01c8062efa895146101d657806301ffc9a7146101d15780631df47f80146101cc5780631fe543e3146101c7578063248a9ca3146101c2578063286eca7f146101bd5780632f2ff15d146101b857806331c58858146101b357806336566f06146101ae57806336568abe146101a957806339ec68a3146101a45780633ca6915f1461019f57806340e58ee51461019a57806344ce2671146101955780635c975abb146101905780635cb6dfff1461018b57806361d49ea81461018657806364df049e146101815780636be5361e1461017c57806378c3a5dd1461017757806391d1485414610172578063962626e81461016d578063a217fddf14610168578063bc20805714610163578063d547741f1461015e578063d7eb82a714610159578063fad8269f146101545763faf7d65e1461014f57600080fd5b6124bb565b612264565b6121fa565b61219d565b611fc8565b611f8e565b611a48565b6119ca565b6118ff565b61166d565b61161b565b61126f565b6111f9565b6111b8565b611143565b611021565b610e2b565b610c5b565b610abc565b6109bf565b610983565b61091b565b610813565b6107c6565b61071c565b61051c565b61043a565b346104355760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104355760043560243590600190600260ff835460081c161461040b5761024f6102007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff6001541617600155565b610257614904565b61025f614666565b81610274826000526005602052604060002090565b01805464ffffffffff90818160a01c16946102976102928888612a59565b612a76565b918388159182156103fc575b50506103d257855b8281111561037557505082547fffffffffffffff0000000000ffffffffffffffffffffffffffffffffffffffff16911660a01b78ffffffffff0000000000000000000000000000000000000000161790557fddd9a1ac1ae0095c1389781239f4f4280ebfb649201b0556f78e77fa289e91839261033f90604051938493846040919493926060820195825260208201520152565b0390a16103736101007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff6001541617600155565b005b806103cc6103a184936103928a6000526003602052604060002090565b90600052602052604060002090565b60057fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b016102ab565b60046040517f67909b15000000000000000000000000000000000000000000000000000000008152fd5b60c81c168311905083386102a3565b60046040517f1bbee726000000000000000000000000000000000000000000000000000000008152fd5b600080fd5b346104355760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610435576004357fffffffff00000000000000000000000000000000000000000000000000000000811680910361043557807f7965db0b00000000000000000000000000000000000000000000000000000000602092149081156104cf575b506040519015158152f35b7f01ffc9a700000000000000000000000000000000000000000000000000000000915014386104c4565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361043557565b346104355760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104355760043573ffffffffffffffffffffffffffffffffffffffff811680910361043557610574614666565b80156105d1576020817fc1b5345cce283376356748dc57f2dfa7120431d016fc7ca9ba641bc65f91411d927fffffffffffffffffffffffff00000000000000000000000000000000000000006006541617600655604051908152a1005b60046040517faa7feadc000000000000000000000000000000000000000000000000000000008152fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60e0810190811067ffffffffffffffff82111761064657604052565b6105fb565b67ffffffffffffffff811161064657604052565b6040810190811067ffffffffffffffff82111761064657604052565b6060810190811067ffffffffffffffff82111761064657604052565b610400810190811067ffffffffffffffff82111761064657604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761064657604052565b604051906107028261067b565b565b67ffffffffffffffff81116106465760051b60200190565b346104355760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104355760243567ffffffffffffffff811161043557366023820112156104355780600401359061077782610704565b9061078560405192836106b4565b82825260209260248484019160051b8301019136831161043557602401905b8282106107b7576103738460043561472c565b813581529084019084016107a4565b346104355760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104355760043560005260006020526020600160406000200154604051908152f35b346104355760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104355760043561084d614666565b80600052600560205260016040600020015464ffffffffff808260c81c169160a01c16106108f1576108ec816108dc60026108b37f3b1b1a7c6b021e524cac489566ae6d22e8dde1b38bcc164bb70490fa21daf97c956000526005602052604060002090565b017fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff8154169055565b6040519081529081906020820190565b0390a1005b60046040517ff9250d0c000000000000000000000000000000000000000000000000000000008152fd5b346104355760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610435576103736004356109586104f9565b90806000526000602052610973600160406000200154614ae6565b614b60565b600091031261043557565b346104355760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610435576020600754604051908152f35b346104355760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610435576109f6614666565b60015460ff811615610a5f5750610a0b614904565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00600154166001557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6020604051338152a1005b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00600191610a8b6148ce565b16176001557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a1005b346104355760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261043557610af36104f9565b3373ffffffffffffffffffffffffffffffffffffffff821603610b1c5761037390600435614c43565b60046040517f6697b232000000000000000000000000000000000000000000000000000000008152fd5b60061115610b5057565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b906006821015610b505752565b9193959490946104c091610ba38484810198610b7f565b64ffffffffff806020971687860152604095168585015260609788850152608084015260a083016000905b868210610c42575050506104a08201528551938490526104e001948201936000915b848310610c005750505050505090565b8551805173ffffffffffffffffffffffffffffffffffffffff168852808501511515888601528101511515878201529581019594830194600190920191610bf0565b825160ff16815291860191600191909101908601610bce565b34610435576040807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610435576104008151610c9981610697565b369037600090600435825260036020528082206024358352602052808220815191610cc38361062a565b81549260ff84166006811015610d935790610d8f929181526020810193610d1464ffffffffff610cff818960081c16889064ffffffffff169052565b8484019760301c16879064ffffffffff169052565b60018101546060830190815260028201549060808401918252610d7c610d70610d526004610d446003880161302e565b9660a0890197885201613300565b9560c081019687525198610d658a610b46565b5164ffffffffff1690565b985164ffffffffff1690565b9051915192519351945197889788610b8c565b0390f35b6024867f4e487b710000000000000000000000000000000000000000000000000000000081526021600452fd5b9060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8301126104355760043567ffffffffffffffff9283821161043557806023830112156104355781600401359384116104355760248460051b83010111610435576024019190565b3461043557610e3936610dc0565b610e416146c9565b60005b818110610e7d57507f1f0def5d5179f4d53a0dafd78f3ae044c7cbf799630739fd50674bbec8c356b8916108ec60405192839283612ab0565b610e8881838561294f565b3590610e9e826000526005602052604060002090565b91610eb8610eb4600285015460ff9060401c1690565b1590565b610ff757600180930190610eea610ee0610edb845464ffffffffff9060c81c1690565b6129c3565b64ffffffffff1690565b610f02610ef885888a61294f565b60208101906129f7565b9260005b848110610f7857505050610ee0610292610f729493610f2493612a59565b7fffff0000000000ffffffffffffffffffffffffffffffffffffffffffffffffff7dffffffffff0000000000000000000000000000000000000000000000000083549260c81b169116179055565b01610e44565b610f828185612a59565b610f8d828786612a66565b35908115610fb9579089610fb1819493610392876000526003602052604060002090565b015501610f06565b6040517f795bfe85000000000000000000000000000000000000000000000000000000008152600481018590526024810191909152604490fd5b0390fd5b60046040517fe7d1a70d000000000000000000000000000000000000000000000000000000008152fd5b346104355760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261043557600435600260ff60015460081c161461040b576110946102007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff6001541617600155565b8060005260056020526040600020611105610eb464ffffffffff600184015460a01c169260036020526110dc8460406000209064ffffffffff16600052602052604060002090565b906110f960026110ed845460ff1690565b92015460281c60ff1690565b90600483015492614558565b6103d25761111291613e95565b6103736101007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff6001541617600155565b346104355760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104355761117a6104f9565b6044359060ff821682036104355760643564ffffffffff81168103610435576084359061ffff8216820361043557610d8f936108dc9360043561256d565b346104355760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261043557602060ff600154166040519015158152f35b346104355760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261043557600435600052600260205260806040600020600181549101546040519160ff81161515835264ffffffffff90818160081c16602085015260301c1660408301526060820152f35b346104355760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610435576024356044356112ac6148ce565b6004906112c482356000526002602052604060002090565b9081549264ffffffffff808560081c169460301c16916112f283610392876000526003602052604060002090565b906003611300835460ff1690565b61130981610b46565b036115f25760408051602081018981528183018490529194919061135881606081015b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018352826106b4565b5190209560019687850154036115ca578661138461137f848701938454938491015461255e565b612a4b565b90600386016000805b838110611499576103738d8d8d7ff7ab5a65307ab9788b10eab6a0e173842698dc9772bc3e58eaac1d6e0315b0598e6113f18f8f600282015560047fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b518481526020810183905260046040820152606090a161149261141e846000526005602052604060002090565b60065473ffffffffffffffffffffffffffffffffffffffff169061148c61148461145e8784015473ffffffffffffffffffffffffffffffffffffffff1690565b9261147e6114776002835493015461ffff9060301c1690565b61ffff1690565b90612c09565b612710900490565b916142ad565b0190614061565b6114ad8e6114a683612bf3565b1c60ff1690565b9160ff831690811580156115c1575b61157f578d821b908181166115575717928d929187916114f9906114e08589612c28565b90919060ff8084549260031b9316831b921b1916179055565b14611505575b0161138d565b6115526115128289612c41565b50740100000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff825416179055565b6114ff565b898d517f8ce0d24b000000000000000000000000000000000000000000000000000000008152fd5b8e89610ff38f8f519384937fa06986c7000000000000000000000000000000000000000000000000000000008552840160209093929193604081019481520152565b508582116114bc565b5083517fb06ec8f9000000000000000000000000000000000000000000000000000000008152fd5b826040517fc38434ab000000000000000000000000000000000000000000000000000000008152fd5b346104355760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261043557602073ffffffffffffffffffffffffffffffffffffffff60065416604051908152f35b346104355761167b36610dc0565b906001600260ff825460081c161461040b576116be6102007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff6001541617600155565b6116c66148ce565b6116ce612c59565b916116d884612c72565b9360005b818110611752577f151b7b4fba4f2f307fc85d2e1759f3691da9606509751f0f40fccf193e418e4d61033f8787602081015180611724575b5050604051918291339083612df8565b61174561174b925173ffffffffffffffffffffffffffffffffffffffff1690565b336142ad565b8380611714565b80856117608693858761294f565b82813591611778836000526005602052604060002090565b928b61178e855461178887614612565b90612a59565b926117a96117a160209283810190612cf0565b969093612d51565b51838152816117b787612d65565b910190815260005b868110611806575050505050856117de6118009594936117fa93612c09565b92015473ffffffffffffffffffffffffffffffffffffffff1690565b906143ef565b016116dc565b839597999a508681939597995061181d9294612db4565b80359061183882610392896000526003602052604060002090565b90611844825460ff1690565b9061184e82610b46565b60048092036118d6578f9493926118b9928861186d9301359101612c41565b5061187981848b6144cb565b75010000000000000000000000000000000000000000007fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff825416179055565b6118c4828551612d51565b520193918b98979593918d97956117bf565b506040517fc38434ab000000000000000000000000000000000000000000000000000000008152fd5b346104355760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104355760043560009081526005602090815260409182902080546001820154600290920154845191825273ffffffffffffffffffffffffffffffffffffffff83169382019390935264ffffffffff60a083811c82168387015260c89390931c811660608301528316608082015260ff602884901c81169282019290925261ffff603084901c1660c08201529190921c909116151560e082015261010090f35b346104355760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261043557602060ff611a3c611a086104f9565b6004356000526000845260406000209073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b54166040519015158152f35b611a5136610dc0565b600260ff60015460081c161461040b57611a926102007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff6001541617600155565b611a9a6148ce565b611aa2612c59565b611aaa612c59565b91611ab481612ea7565b93349160005b818110611c8657505050611c5c57602081015180611b3e575b50507f1e473be843779c10566d945a4adf38c5fa2f3585a52fc906f1d9e502cf3798879181602061033f93015180611b16575b5050604051918291339083612f6b565b611745611b37925173ffffffffffffffffffffffffffffffffffffffff1690565b3880611b06565b611b9673ffffffffffffffffffffffffffffffffffffffff9492947f00000000000000000000000000000000000ea4af05656c17b90f4d64add29e1d16945173ffffffffffffffffffffffffffffffffffffffff1690565b90843b15610435576040517fda3e8ce400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9290921660048301523360248301523060448301526064820152926000908490608490829084905af1918215611c57577f1e473be843779c10566d945a4adf38c5fa2f3585a52fc906f1d9e502cf3798879361033f93611c3e575b5091819350611ad3565b80611c4b611c519261064b565b80610978565b38611c34565b612c1c565b60046040517f87b71f66000000000000000000000000000000000000000000000000000000008152fd5b611c91818385612f2b565b611c9e6060820182612cf0565b80915015611f6457611cbb82356000526005602052604060002090565b91611cdd600184015473ffffffffffffffffffffffffffffffffffffffff1690565b916040820135611ded575b91849392611cf88b93968d612d51565b5186358152611d0682612d65565b6020820152600094855b838110611d62575050956040611d3b611d429360019960208501359384910152604084013590612a59565b91356134df565b82611d51575b50505001611aba565b611d5a926143ef565b388781611d48565b909192939596979450611d8281611d7c6060880188612cf0565b90612db4565b6004611da1611d99600286015460ff9060281c1690565b8835846141b2565b611daa81610b46565b14611dd3575b9060019135611dc3826020870151612d51565b5201908c94979695939291611d10565b9690611de460019261178885614612565b97909150611db0565b9673ffffffffffffffffffffffffffffffffffffffff8381169081611e2d575050611e2790611e2160408401358654612c09565b90612aa3565b96611ce8565b8a5192999273ffffffffffffffffffffffffffffffffffffffff169181831603611e78575050611e6260408301358554612c09565b611e7160208b01918251612a59565b9052611ce8565b60208b019182519182611eb1575b50505073ffffffffffffffffffffffffffffffffffffffff84168a52611e7160408401358654612c09565b7f00000000000000000000000000000000000ea4af05656c17b90f4d64add29e1d1691823b15610435576040517fda3e8ce400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9290921660048301523360248301523060448301526064820152906000908290608490829084905af18015611c5757611f51575b8080611e86565b80611c4b611f5e9261064b565b38611f4a565b60046040517fc7017d52000000000000000000000000000000000000000000000000000000008152fd5b346104355760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261043557602060405160008152f35b60607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261043557600435604435600260ff60015460081c161461040b576120396102007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff6001541617600155565b6120416148ce565b612055826000526005602052604060002090565b6120818261207a600184015473ffffffffffffffffffffffffffffffffffffffff1690565b9254612c09565b9073ffffffffffffffffffffffffffffffffffffffff8082166120b45750503403611c5c57611112915b602435906134df565b93919334612173577f00000000000000000000000000000000000ea4af05656c17b90f4d64add29e1d1693843b15610435576040517fda3e8ce400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9290921660048301523360248301523060448301526064820152926000908490608490829084905af1928315611c575761111293612160575b506120ab565b80611c4b61216d9261064b565b3861215a565b60046040517fe2a8f8a0000000000000000000000000000000000000000000000000000000008152fd5b346104355760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610435576103736004356121da6104f9565b908060005260006020526121f5600160406000200154614ae6565b614c43565b346104355760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104355760443573ffffffffffffffffffffffffffffffffffffffff811681036104355761225a6020916024356004356133a6565b6040519015158152f35b346104355761227236610dc0565b6001600260ff825460081c161461040b576122b46102007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff6001541617600155565b6122bc6148ce565b6122c4612c59565b926122ce83612c72565b9260005b818110612319577fd53f2bb6fed83c8a1662fd984e0882cef7bc2c6dd8d4d8d482ca931945efd61961033f8688602081015180611724575050604051918291339083612df8565b80866123278693858761294f565b8781359161233f836000526005602052604060002090565b9260208083019161235c886123548587612cf0565b979050612d51565b51918183528061236b87612d65565b930192835260005b86811061239a57505050505050906117fa856117de61239495948454612c09565b016122d2565b8597999a5084969850611d7c8193956123b4939597612cf0565b8035906123cf82610392876000526003602052604060002090565b906123db825460ff1690565b908b8660049283860194855496816123f38993610b46565b86811061247f575b5050500135938410159050612444575061241b8f94939261242792612c41565b506118798184896144cb565b612432828751612d51565b5201918b98979593918e979593612373565b604080517fa06986c7000000000000000000000000000000000000000000000000000000008152918201888152602081018690528291010390fd5b6124a0945061249a6002610eb49597015460ff9060281c1690565b91614558565b6118d65786906124b0868a613e95565b908d918538806123fb565b346104355760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261043557602061225a60043560009080825260038452604082206024358352845260ff6002604080852094838654169481526005885220015460281c1690600483015492614558565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b8115612568570690565b61252f565b90919493929461257b614666565b60ff8116600281106128f6576020106128cc5761ffff84166109c481116128a2576125d49061271060ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85011691850204840361255e565b6128785764ffffffffff8616603c811090811561286c575b50612842577f44ab42484886e3b9dfa09fe03c00b19e3386faaa7313d5de2b4bcd7d1453dd799361283d9160075497846126308a6000526005602052604060002090565b5561268c86600161264b8c6000526005602052604060002090565b019073ffffffffffffffffffffffffffffffffffffffff167fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055565b6126de8260026126a68c6000526005602052604060002090565b01907fffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffff65ff000000000083549260281b169116179055565b61272a8160026126f88c6000526005602052604060002090565b019064ffffffffff167fffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000825416179055565b61277e8360026127448c6000526005602052604060002090565b01907fffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffff67ffff00000000000083549260301b169116179055565b6127cb60026127978b6000526005602052604060002090565b01680100000000000000007fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff825416179055565b6127d489613f21565b6127e86127e360075460010190565b600755565b6040519586958a879464ffffffffff60a09573ffffffffffffffffffffffffffffffffffffffff61ffff9660ff959b9a9660c08b019c8b5260208b015216604089015216606087015216608085015216910152565b0390a1565b60046040517f06201c01000000000000000000000000000000000000000000000000000000008152fd5b610e10915011386125ec565b60046040517f490bbdd0000000000000000000000000000000000000000000000000000000008152fd5b60046040517f36d36c7c000000000000000000000000000000000000000000000000000000008152fd5b60046040517fbaa3711d000000000000000000000000000000000000000000000000000000008152fd5b60046040517fe8a119d4000000000000000000000000000000000000000000000000000000008152fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b919081101561298f5760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc181360301821215610435570190565b612920565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b90600164ffffffffff809316019182116129d957565b612994565b91909164ffffffffff808094169116019182116129d957565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610435570180359067ffffffffffffffff821161043557602001918160051b3603831361043557565b90600182018092116129d957565b919082018092116129d957565b919081101561298f5760051b0190565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82019182116129d957565b919082039182116129d957565b916020908082850183865252604091828501946005958484881b83010196866000935b868510612ae65750505050505050505090565b9091929394959697987fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc082820301855289357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc18436030181121561043557830180358252878101357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe182360301811215610435570187813591019167ffffffffffffffff82116104355781861b918236038413610435577f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff908c8b840152808d8401521161043557600192828a939284936060938483013701019b01950195019397969594929190612ad3565b908160031b91808304600814901517156129d957565b818102929181159184041417156129d957565b6040513d6000823e3d90fd5b919091602083101561298f57601f908360051c01921690565b805482101561298f5760005260206000200190600090565b60405190612c668261065f565b60006020838281520152565b90612c7c82610704565b6040612c8a815192836106b4565b8382527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0612cb88395610704565b0191600091825b848110612ccd575050505050565b6020908251612cdb8161065f565b85815282606081830152828601015201612cbf565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610435570180359067ffffffffffffffff821161043557602001918160061b3603831361043557565b80511561298f5760200190565b805182101561298f5760209160051b010190565b90612d6f82610704565b612d7c60405191826106b4565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0612daa8294610704565b0190602036910137565b919081101561298f5760061b0190565b90815180825260208080930193019160005b828110612de4575050505090565b835185529381019392810192600101612dd6565b909291926040808301908084528251809252606084019160608160051b860101916020809501936000915b86848410612e4e57505050505073ffffffffffffffffffffffffffffffffffffffff91509416910152565b80612e97877fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08c6001969798999a0301875285838b518051845201519181858201520190612dc4565b9701930193019194939290612e23565b90612eb182610704565b604090612ec0825191826106b4565b8381527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0612eee8295610704565b0191600091825b848110612f03575050505050565b6020908351612f118161067b565b858152826060818301528686830152828501015201612ef5565b919081101561298f5760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8181360301821215610435570190565b9192909260409384840194808552815180965260609586860191878260051b880101926020809501986000925b848410612fc85750505050506107029394955094019073ffffffffffffffffffffffffffffffffffffffff169052565b90919293948680827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08d600195030187528d5190815181528580613017858501518a878601528a850190612dc4565b9301519101529c0194019401929994939190612f98565b6040805160009390929190835b602080601f880110156132f0576104006020926132e46001936132d98954916132b26131176132628c613212896131c260ff9761307c838a8d1660ff169052565b61308f8184018a8d60081c1660ff169052565b6130a28584018a8d60101c1660ff169052565b888b6102006060956130bd878201858560181c1660ff169052565b6130d26080958585888501921c1660ff169052565b61317860a0976130eb898401878760281c1660ff169052565b61312860c09b6131048d8601898960301c1660ff169052565b60e09e8f8601898960381c1660ff169052565b87876101008701921c1660ff169052565b61313d6101208401878760481c1660ff169052565b6131526101408401878760501c1660ff169052565b6131676101608401878760581c1660ff169052565b85856101808501921c1660ff169052565b61318d6101a08201858560681c1660ff169052565b6131a26101c08201858560701c1660ff169052565b6131b76101e08201858560781c1660ff169052565b01921c1660ff169052565b6131d76102208c01888b60881c1660ff169052565b6131ec6102408c01888b60901c1660ff169052565b6132016102608c01888b60981c1660ff169052565b86896102808d01921c1660ff169052565b6132276102a08a01868960a81c1660ff169052565b61323c6102c08a01868960b01c1660ff169052565b6132516102e08a01868960b81c1660ff169052565b84876103008b01921c1660ff169052565b6132776103208801848760c81c1660ff169052565b61328c6103408801848760d01c1660ff169052565b6132a16103608801848760d81c1660ff169052565b82856103808901921c1660ff169052565b6132c76103a08601828560e81c1660ff169052565b6103c08501908360f01c1660ff169052565b60f81c6103e0830152565b0194019501949261303b565b5050929350505061070282610697565b90815461330c81610704565b9260409361331c855191826106b4565b828152809460208092019260005281600020906000935b85851061334257505050505050565b600184819284516133528161067b565b865473ffffffffffffffffffffffffffffffffffffffff8116825260ff90818160a01c1615158584015260a81c16151586820152815201930194019391613333565b6201000082101561298f570190600090565b73ffffffffffffffffffffffffffffffffffffffff60ff9316600052600460205260406000209060005260205260016133e68260081c6040600020613394565b93905492161b9160031b1c16151590565b8054680100000000000000008110156106465761341991600182018155612c41565b9190916134b05780518254602083015160409093015173ffffffffffffffffffffffffffffffffffffffff9092167fffffffffffffffffffff000000000000000000000000000000000000000000009091161791151560a01b74ff0000000000000000000000000000000000000000169190911790151560a81b75ff00000000000000000000000000000000000000000016179055565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b929190801580156138d2575b6138a857613503846000526005602052604060002090565b936002850194855460409660ff82891c161561387f576135238686612a59565b9161353e610ee060018096015464ffffffffff9060c81c1690565b917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff92838501116138565761358187610392886000526003602052604060002090565b9161358d835460ff1690565b9061359782610b46565b86821161381e5760281c60ff16936135ae82610b46565b81156137cb575b50875b85811061360f575050985194855250505050602081019190915260408101919091523360608201529091507f9a711314e8e01b50116aefb9d50edc1a6b06e39986010af70d18671666586d0e90806080810161283d565b61361a33828a6133a6565b61378c57808914801561376f57845b6004918282018a815401938985116137295750918f916136648c9695938b9560006136526106f5565b338152928160208501528301526133f7565b61366f33868f61444f565b61367d575b505050016135b8565b61368686610b46565b8486036136745764ffffffffff90816136a8825464ffffffffff9060081c1690565b16156136ce575b5050146136bf575b853880613674565b6136c9818a613c62565b6136b7565b6136ec613722926136e48a5464ffffffffff1690565b9042166129de565b7fffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000ff65ffffffffff0083549260081b169116179055565b38806136af565b9350505050610ff389928e519384937fca10b936000000000000000000000000000000000000000000000000000000008552840160209093929193604081019481520152565b613787826103928b6000526003602052604060002090565b613629565b8b517f190f2750000000000000000000000000000000000000000000000000000000008152600481018990526024810191909152336044820152606490fd5b868911156135b55788016138076137f0826103928b6000526003602052604060002090565b866137fc825460ff1690565b600483015492614558565b156135b557613817915087613e95565b84386135b5565b8b517fca10b93600000000000000000000000000000000000000000000000000000000815260048101899052602481018a9052604490fd5b60048a517f5ee0d7b4000000000000000000000000000000000000000000000000000000008152fd5b600488517fe7d1a70d000000000000000000000000000000000000000000000000000000008152fd5b60046040517f558947cf000000000000000000000000000000000000000000000000000000008152fd5b5081156134eb565b90816020910312610435575190565b61393e613913613903836000526003602052604060002090565b6001600052602052604060002090565b60027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b64ffffffffff61399d814216613961613903856000526003602052604060002090565b907fffffffffffffffffffffffffffffffffffffffffff0000000000ffffffffffff6affffffffff00000000000083549260301b169116179055565b6040517f5d3b1d300000000000000000000000000000000000000000000000000000000081527f8af398995b04c28e9951adb9721ef74c74f93e6a478f39e7e0777be13527e7ef60048201527f00000000000000000000000000000000000000000000000000000000000002de67ffffffffffffffff166024820152600360448201526207a1206064820152600160848201529160208360a48160007f000000000000000000000000271682deb8c4e0901d1a1550ad2e64d568e6990973ffffffffffffffffffffffffffffffffffffffff165af1928315611c5757600093613c32575b50613aa0613a99846000526002602052604060002090565b5460ff1690565b613c08577f34e010a4ef37e7b53b3d02e76e84b745a250daa244a2768dabaf7c0c1947963e613be784613b8061283d95613b33613b087ff7ab5a65307ab9788b10eab6a0e173842698dc9772bc3e58eaac1d6e0315b059996000526002602052604060002090565b60017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b8516613b49836000526002602052604060002090565b907fffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000ff65ffffffffff0083549260081b169116179055565b613bc8613b97826000526002602052604060002090565b66010000000000007fffffffffffffffffffffffffffffffffffffffffff0000000000ffffffffffff825416179055565b6040805185815260016020820152908101919091529081906060820190565b0390a160408051918252600160208301526002908201529081906060820190565b60046040517ff9012132000000000000000000000000000000000000000000000000000000008152fd5b613c5491935060203d8111613c5b575b613c4c81836106b4565b8101906138da565b9138613a81565b503d613c42565b90613c7e61391382610392856000526003602052604060002090565b64ffffffffff91613ca383421661396184610392856000526003602052604060002090565b6040517f5d3b1d300000000000000000000000000000000000000000000000000000000081527f8af398995b04c28e9951adb9721ef74c74f93e6a478f39e7e0777be13527e7ef60048201527f00000000000000000000000000000000000000000000000000000000000002de67ffffffffffffffff166024820152600360448201526207a12060648201526001608482015260208160a48160007f000000000000000000000000271682deb8c4e0901d1a1550ad2e64d568e6990973ffffffffffffffffffffffffffffffffffffffff165af1908115611c5757600091613e77575b50613d9e613a99826000526002602052604060002090565b613c0857613e5281613e337ff7ab5a65307ab9788b10eab6a0e173842698dc9772bc3e58eaac1d6e0315b05996613e03613b087f34e010a4ef37e7b53b3d02e76e84b745a250daa244a2768dabaf7c0c1947963e966000526002602052604060002090565b613e1d818716613b49856000526002602052604060002090565b8616613961836000526002602052604060002090565b6040519182918686846040919493926060820195825260208201520152565b0390a161283d6040519283928360409060029294936060820195825260208201520152565b613e8f915060203d8111613c5b57613c4c81836106b4565b38613d86565b600161070292826000526003602052604060002081600052602052613ee3604060002060057fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b7ff7ab5a65307ab9788b10eab6a0e173842698dc9772bc3e58eaac1d6e0315b059606060405185815283602082015260056040820152a10190614061565b80600052600360205260406000206001600052602052604060002090600482015491613f57826000526005602052604060002090565b6002810180549094919060281c60ff168203613f7a5750505061070291506138e9565b8293614016600161403493613fd67ff7ab5a65307ab9788b10eab6a0e173842698dc9772bc3e58eaac1d6e0315b059969760017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b01740100000000000000000000000000000000000000007fffffffffffffff0000000000ffffffffffffffffffffffffffffffffffffffff825416179055565b60408051918252600160208301819052908201529081906060820190565b0390a161403f575050565b6136ec614054610702935464ffffffffff1690565b64ffffffffff42166129de565b90816000526003602052604060002081600052602052604060002091600483015492614097826000526005602052604060002090565b9360028501906140b56140af835460ff9060281c1690565b60ff1690565b81036140c8575050506107029250613c62565b91937ff7ab5a65307ab9788b10eab6a0e173842698dc9772bc3e58eaac1d6e0315b059919361411c8660017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b600190960180547fffffffffffffff0000000000ffffffffffffffffffffffffffffffffffffffff1660a083901b78ffffffffff00000000000000000000000000000000000000001617905564ffffffffff956141916040519283928360409060019294936060820195825260208201520152565b0390a161419d57505050565b54610702926136ec9164ffffffffff166136e4565b90929192602082359201356141d1826000526003602052604060002090565b83600052602052604060002060ff815416956004820191825480926141f58a610b46565b8960048110614262575b50505050821015614225579161421c611879926107029594612c41565b509283916144cb565b50506040517fa06986c700000000000000000000000000000000000000000000000000000000815260048101919091526024810191909152604490fd5b61426b93614558565b156142835761427a8585613e95565b388181896141ff565b60046040517fc38434ab000000000000000000000000000000000000000000000000000000008152fd5b919073ffffffffffffffffffffffffffffffffffffffff81166142f8575090610702915a917f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26149b1565b803b156143c5576040517fa9059cbb000000000000000000000000000000000000000000000000000000006020820190815273ffffffffffffffffffffffffffffffffffffffff9094166024820152604481019290925260009283928390614363816064810161132c565b51925af161436f61493b565b901561439b57805180614380575050565b81602080610eb4936143959501019101614999565b61439b57565b60046040517ff1568f95000000000000000000000000000000000000000000000000000000008152fd5b60046040517f09ee12d5000000000000000000000000000000000000000000000000000000008152fd5b9173ffffffffffffffffffffffffffffffffffffffff80825116921682811460001461442a5750602091500180519182018092116129d95752565b90602081019283518061443e575b50505252565b61444891336142ad565b3880614438565b909173ffffffffffffffffffffffffffffffffffffffff16600052600460205260406000209060005260205261448c8160081c6040600020613394565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600160ff849594549360031b94161b82841c17831b921b1916179055565b90915460ff8160a01c16908115614549575b8115614528575b506144ed575050565b6040517f7f7f26da00000000000000000000000000000000000000000000000000000000815260048101919091526024810191909152604490fd5b73ffffffffffffffffffffffffffffffffffffffff163314159050386144e4565b905060ff8160a81c16906144dd565b929091925464ffffffffff91828260081c16946006851015610b5057600185149586614608575b866145fd575b50856145f0575b5050831561459b575b50505090565b600283149350909183156145da575b50826145bb575b5050388080614595565b90915060301c811662015180018181116129d9571642101538806145b1565b60039193506145e881610b46565b1491386145aa565b60ff16119350388061458c565b421015955038614585565b801515965061457f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60ff60028354930154926146546127109161ffff8660301c16830390612c09565b049260281c1601908115612568570490565b3360009081527fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5602052604090205460ff161561469f57565b60046040517f30cd7471000000000000000000000000000000000000000000000000000000008152fd5b3360009081527fee57cd81e84075558e8fcc182a1f4393f91fc97f963a136e66b7f949a62f319f602052604090205460ff161561470257565b60046040517f7c214f04000000000000000000000000000000000000000000000000000000008152fd5b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000271682deb8c4e0901d1a1550ad2e64d568e6990916803303614897575080600052600260205260406000205460ff811661478757505050565b64ffffffffff9060081c166147ba610ee06147ac846000526002602052604060002090565b5460301c64ffffffffff1690565b916147d383610392846000526003602052604060002090565b60026147e0825460ff1690565b6147e981610b46565b146147f6575b5050505050565b6148666148547ff7ab5a65307ab9788b10eab6a0e173842698dc9772bc3e58eaac1d6e0315b0599661484f60019460037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b612d44565b51926000526002602052604060002090565b015561488a6040519283928360409060039294936060820195825260208201520152565b0390a138808080806147ef565b604490604051907f1cf993f40000000000000000000000000000000000000000000000000000000082523360048301526024820152fd5b60ff600154166148da57565b60046040517f1309a563000000000000000000000000000000000000000000000000000000008152fd5b60ff600154161561491157565b60046040517f6cd60201000000000000000000000000000000000000000000000000000000008152fd5b3d15614994573d9067ffffffffffffffff8211610646576040519161498860207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601846106b4565b82523d6000602084013e565b606090565b90816020910312610435575180151581036104355790565b6149c682849395600080809781948294f11590565b6149d1575b50505050565b73ffffffffffffffffffffffffffffffffffffffff16803b15614ae257604051937fd0e30db0000000000000000000000000000000000000000000000000000000008552838560048186865af1938415611c5757614a8a95602095614acf575b506040518096819582947fa9059cbb000000000000000000000000000000000000000000000000000000008452600484016020909392919373ffffffffffffffffffffffffffffffffffffffff60408201951681520152565b03925af18015611c5757614aa1575b8080806149cb565b614ac19060203d8111614ac8575b614ab981836106b4565b810190614999565b5038614a99565b503d614aaf565b80611c4b614adc9261064b565b38614a31565b8280fd5b80600052600060205260ff614b1f3360406000209073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b541615614b295750565b604490604051907fe2517d3f0000000000000000000000000000000000000000000000000000000082523360048301526024820152fd5b6000908082528160205260ff614b9984604085209073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b5416614c3d5780825281602052614bd383604084209073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b60017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008254161790557f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d73ffffffffffffffffffffffffffffffffffffffff3394169280a4600190565b50905090565b6000908082528160205260ff614c7c84604085209073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b541615614c3d5780825281602052614cb783604084209073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0081541690557ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b73ffffffffffffffffffffffffffffffffffffffff3394169280a460019056fea2646970667358221220a125cb17f3508dc82892b7bcfc8e7235a8793e3b5b448661287891a1a590f48364736f6c63430008140033

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

000000000000000000000000b5a9e5a319c7fda551a30be592c77394bf935c6f000000000000000000000000842ca39dfd984d4349ce8d8c95577e2bf42f4db0000000000000000000000000c8c57e4c73c71f72ca0a7e043e5d2d144f98ef13000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000000000000000ea4af05656c17b90f4d64add29e1d8af398995b04c28e9951adb9721ef74c74f93e6a478f39e7e0777be13527e7ef000000000000000000000000271682deb8c4e0901d1a1550ad2e64d568e6990900000000000000000000000000000000000000000000000000000000000002de

-----Decoded View---------------
Arg [0] : _owner (address): 0xB5a9e5a319c7fDa551a30BE592c77394bF935c6f
Arg [1] : _operator (address): 0x842cA39Dfd984d4349Ce8D8c95577E2Bf42f4dB0
Arg [2] : _protocolFeeRecipient (address): 0xC8C57e4C73c71f72cA0a7e043E5D2D144F98ef13
Arg [3] : wrappedNativeToken (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
Arg [4] : _transferManager (address): 0x00000000000ea4af05656C17b90f4d64AdD29e1d
Arg [5] : keyHash (bytes32): 0x8af398995b04c28e9951adb9721ef74c74f93e6a478f39e7e0777be13527e7ef
Arg [6] : vrfCoordinator (address): 0x271682DEB8C4E0901D1a1550aD2e64D568E69909
Arg [7] : subscriptionId (uint64): 734

-----Encoded View---------------
8 Constructor Arguments found :
Arg [0] : 000000000000000000000000b5a9e5a319c7fda551a30be592c77394bf935c6f
Arg [1] : 000000000000000000000000842ca39dfd984d4349ce8d8c95577e2bf42f4db0
Arg [2] : 000000000000000000000000c8c57e4c73c71f72ca0a7e043e5d2d144f98ef13
Arg [3] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [4] : 00000000000000000000000000000000000ea4af05656c17b90f4d64add29e1d
Arg [5] : 8af398995b04c28e9951adb9721ef74c74f93e6a478f39e7e0777be13527e7ef
Arg [6] : 000000000000000000000000271682deb8c4e0901d1a1550ad2e64d568e69909
Arg [7] : 00000000000000000000000000000000000000000000000000000000000002de


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]
[ 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.