ETH Price: $3,379.39 (+0.12%)

Contract

0x628015A6f2e6da491Ad572210C264107DB294f6E
 
Transaction Hash
Method
Block
From
To
0x7a13e790cdd0fcf0d0059830d710e15fe04a6d31a910eae6da6635cc82d72fe0 Buy Entry(pending)2024-11-23 7:27:171 hr ago1732346837IN
0x628015A6...7DB294f6E
0 ETH(Pending)(Pending)
0x1c512a63dc9318671a43ee38b921317b2a2debe3bfd39894861e39695f69c975 Buy Entry(pending)2024-11-19 16:24:143 days ago1732033454IN
0x628015A6...7DB294f6E
0 ETH(Pending)(Pending)
0xf69fbb4f29600f2e2d579ff3a0aa5fd20236e8d03ad30c35768253b7d6a76d11 Buy Entry(pending)2024-11-03 21:39:2419 days ago1730669964IN
0x628015A6...7DB294f6E
0 ETH(Pending)(Pending)
0x74ab21fafd5ff7ed3d58fc201ba98ff6d94a637ec0944725f0f8f18d74de6562 Buy Entry(pending)2024-11-03 3:19:0220 days ago1730603942IN
0x628015A6...7DB294f6E
0 ETH(Pending)(Pending)
Buy Entry212455582024-11-22 20:08:4712 hrs ago1732306127IN
0x628015A6...7DB294f6E
0.006 ETH0.0008307612.5079017
Buy Entry212447112024-11-22 17:18:2315 hrs ago1732295903IN
0x628015A6...7DB294f6E
0.006 ETH0.001075716.19580581
Buy Entry212442112024-11-22 15:36:5917 hrs ago1732289819IN
0x628015A6...7DB294f6E
0 ETH0.0009867714.85686042
Buy Entry212316132024-11-20 21:24:232 days ago1732137863IN
0x628015A6...7DB294f6E
0.096 ETH0.0009708814.6175461
Set Winner212314922024-11-20 21:00:112 days ago1732136411IN
0x628015A6...7DB294f6E
0 ETH0.0040232922.74962889
Buy Entry212314862024-11-20 20:58:592 days ago1732136339IN
0x628015A6...7DB294f6E
0.012 ETH0.0015148922.80820313
Buy Entry212314862024-11-20 20:58:592 days ago1732136339IN
0x628015A6...7DB294f6E
0 ETH0.0015148922.80820313
Buy Entry212314822024-11-20 20:58:112 days ago1732136291IN
0x628015A6...7DB294f6E
0.096 ETH0.0015541923.3998659
Buy Entry212314512024-11-20 20:51:592 days ago1732135919IN
0x628015A6...7DB294f6E
0.048 ETH0.0015676523.6024852
Buy Entry212313902024-11-20 20:39:472 days ago1732135187IN
0x628015A6...7DB294f6E
0.006 ETH0.0018453827.78391886
Buy Entry212313742024-11-20 20:36:352 days ago1732134995IN
0x628015A6...7DB294f6E
0.006 ETH0.0018613128.02384604
Buy Entry212313722024-11-20 20:36:112 days ago1732134971IN
0x628015A6...7DB294f6E
0.012 ETH0.0019158628.84506167
Buy Entry212313312024-11-20 20:27:592 days ago1732134479IN
0x628015A6...7DB294f6E
0.006 ETH0.0009455914.23685179
Buy Entry212313212024-11-20 20:25:592 days ago1732134359IN
0x628015A6...7DB294f6E
0.006 ETH0.0011987418.04819919
Buy Entry212312532024-11-20 20:12:232 days ago1732133543IN
0x628015A6...7DB294f6E
0 ETH0.0011931717.96429579
Buy Entry212312492024-11-20 20:11:352 days ago1732133495IN
0x628015A6...7DB294f6E
0.012 ETH0.0012160118.30819306
Buy Entry212312262024-11-20 20:06:592 days ago1732133219IN
0x628015A6...7DB294f6E
0.006 ETH0.0013060719.66419795
Buy Entry212312132024-11-20 20:04:232 days ago1732133063IN
0x628015A6...7DB294f6E
0 ETH0.0012402618.67336369
Buy Entry212312052024-11-20 20:02:472 days ago1732132967IN
0x628015A6...7DB294f6E
0.006 ETH0.0012647119.04149791
Buy Entry212312042024-11-20 20:02:352 days ago1732132955IN
0x628015A6...7DB294f6E
0.006 ETH0.0011427317.20488672
Buy Entry212310792024-11-20 19:37:232 days ago1732131443IN
0x628015A6...7DB294f6E
0.048 ETH0.0012173218.32790505
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To
212315032024-11-20 21:02:232 days ago1732136543
0x628015A6...7DB294f6E
2.73 ETH
212315032024-11-20 21:02:232 days ago1732136543
0x628015A6...7DB294f6E
3 ETH
211813282024-11-13 21:02:239 days ago1731531743
0x628015A6...7DB294f6E
3.644 ETH
211813282024-11-13 21:02:239 days ago1731531743
0x628015A6...7DB294f6E
3 ETH
211311672024-11-06 21:02:2316 days ago1730926943
0x628015A6...7DB294f6E
2.858 ETH
211311672024-11-06 21:02:2316 days ago1730926943
0x628015A6...7DB294f6E
3 ETH
210807112024-10-30 20:02:2323 days ago1730318543
0x628015A6...7DB294f6E
3.064 ETH
210807112024-10-30 20:02:2323 days ago1730318543
0x628015A6...7DB294f6E
3 ETH
210305522024-10-23 20:02:2330 days ago1729713743
0x628015A6...7DB294f6E
2.848 ETH
210305522024-10-23 20:02:2330 days ago1729713743
0x628015A6...7DB294f6E
3 ETH
209875442024-10-17 20:02:2336 days ago1729195343
0x628015A6...7DB294f6E
2.342 ETH
209875442024-10-17 20:02:2336 days ago1729195343
0x628015A6...7DB294f6E
3 ETH
209374752024-10-10 20:02:3543 days ago1728590555
0x628015A6...7DB294f6E
2.598 ETH
209374752024-10-10 20:02:3543 days ago1728590555
0x628015A6...7DB294f6E
3 ETH
208800752024-10-02 20:02:2351 days ago1727899343
0x628015A6...7DB294f6E
2.836 ETH
208800752024-10-02 20:02:2351 days ago1727899343
0x628015A6...7DB294f6E
3 ETH
208298752024-09-25 20:02:4758 days ago1727294567
0x628015A6...7DB294f6E
3.104 ETH
208298752024-09-25 20:02:4758 days ago1727294567
0x628015A6...7DB294f6E
3 ETH
207797372024-09-18 20:02:2365 days ago1726689743
0x628015A6...7DB294f6E
2.56 ETH
207797372024-09-18 20:02:2365 days ago1726689743
0x628015A6...7DB294f6E
3 ETH
207296262024-09-11 20:02:2372 days ago1726084943
0x628015A6...7DB294f6E
2.742 ETH
207296262024-09-11 20:02:2372 days ago1726084943
0x628015A6...7DB294f6E
3 ETH
206794772024-09-04 20:02:2379 days ago1725480143
0x628015A6...7DB294f6E
2.4 ETH
206794772024-09-04 20:02:2379 days ago1725480143
0x628015A6...7DB294f6E
3 ETH
206293462024-08-28 20:02:3586 days ago1724875355
0x628015A6...7DB294f6E
2.644 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
ETHFixedLean

Compiler Version
v0.8.4+commit.c7e474f2

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 11 : ETHFixedLean.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.4;

import "@openzeppelin/contracts/access/AccessControl.sol";
import "@chainlink/contracts/src/v0.8/VRFConsumerBase.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";

/// @title Raffles manager (lean, single winner and a fixed amount of ETH as prize)
/// @author Luis Pando
/// @notice It consumes VRF v1 from Chainlink. It has the role
/// "operator" that is the one used by a backend app to make some calls
/// @dev It saves in an ordered array the player wallet and the current
/// entries count. So buying entries has a complexity of O(1)
/// For calculating the winner, from the huge random number generated by Chainlink
/// a normalized random is generated by using the module method, adding 1 to have
/// a random from 1 to entriesCount.
/// So next step is to perform a binary search on the ordered array to get the
/// player O(log n)
/// Example:
/// 0 -> { 1, player1} as player1 buys 1 entry
/// 1 -> {51, player2} as player2 buys 50 entries
/// 2 -> {52, player3} as player3 buys 1 entry
/// 3 -> {53, player4} as player4 buys 1 entry
/// 4 -> {153, player5} as player5 buys 100 entries
/// So the setWinner method performs a binary search on that sorted array to get the upper bound.
/// If the random number generated is 150, the winner is player5. If the random number is 20, winner is player2

contract ETHFixedLean is AccessControl, VRFConsumerBase {
    ////////// CHAINLINK VRF v1 /////////////////
    bytes32 internal keyHash; // chainlink
    uint256 internal fee; // fee paid in LINK to chainlink. 0.1 in Rinkeby, 2 in mainnet

    struct RandomResult {
        uint256 randomNumber; // random number generated by chainlink.
        uint256 nomalizedRandomNumber; // random number % entriesLength + 1. So between 1 and entries.length
    }

    // event sent when the random number is generated by the VRF
    event RandomNumberCreated(
        uint256 indexed idFromMetawin,
        uint256 randomNumber,
        uint256 normalizedRandomNumber
    );

    struct RaffleInfo {
        uint256 id; // raffleId
        uint256 size; // length of the entries array of that raffle
    }

    mapping(uint256 => RandomResult) public requests;
    // map the requestId created by chainlink with the raffle info passed as param when calling getRandomNumber()
    mapping(bytes32 => RaffleInfo) public chainlinkRaffleInfo;

    /////////////// END CHAINKINK VRF V1 //////////////

    error EntryNotAllowed(string errorType);

    // Event sent when the raffle is created by the operator
    event RaffleCreated(uint256 indexed raffleId, uint256 indexed nftId);
    // Event sent when the owner of the nft stakes it for the raffle
    event RaffleStarted(uint256 indexed raffleId, address indexed seller);
    // Event sent when the raffle is finished (either early cashout or successful completion)
    event RaffleEnded(
        uint256 indexed raffleId,
        address indexed winner,
        uint256 amountRaised,
        uint256 randomNumber
    );
    // Event sent when one or more entries are sold (info from the price structure)
    event EntrySold(
        uint256 indexed raffleId,
        address indexed buyer,
        uint256 currentSize,
        uint256 priceStructureId
    );
    // Event sent when a free entry is added by the operator
    event FreeEntry(
        uint256 indexed raffleId,
        address[] buyer,
        uint256 amount,
        uint256 currentSize
    );
    // Event sent when a raffle is asked to cancel by the operator
    event RaffleCancelled(uint256 indexed raffleId, uint256 amountRaised);
    // The raffle is closed successfully and the platform receives the fee
    event FeeTransferredToPlatform(
        uint256 indexed raffleId,
        uint256 amountTransferred
    );
    // When the raffle is asked to be cancelled and 30 days have passed, the operator can call a method
    // to transfer the remaining funds and this event is emitted
    event RemainingFundsTransferred(
        uint256 indexed raffleId,
        uint256 amountInWeis
    );
    // When the raffle is asked to be cancelled and 30 days have not passed yet, the players can call a
    // method to refund the amount spent on the raffle and this event is emitted
    event Refund(
        uint256 indexed raffleId,
        uint256 amountInWeis,
        address indexed player
    );
    event EarlyCashoutTriggered(uint256 indexed raffleId, uint256 amountRaised);
    event SetWinnerTriggered(uint256 indexed raffleId, uint256 amountRaised);
    event StatusChangedInEmergency(uint256 indexed raffleId, uint256 newStatus);
    // Emitted when an entry is cancelled
    event EntryCancelled(
        uint256 indexed raffleId,
        uint256 amountOfEntriesCanceled,
        address player
    );

    struct PriceStructure {
        uint256 id;
        uint48 numEntries;
        uint256 price;
    }
    mapping(uint256 => PriceStructure) public pricesList;

    // Every raffle has a funding structure.
    struct FundingStructure {
        uint128 minimumFundsInWeis;
        uint128 desiredFundsInWeis;
    }
    mapping(uint256 => FundingStructure) public fundingList;

    // In order to calculate the winner, in this struct is saved for each bought the data
    struct EntriesBought {
        uint48 currentEntriesLength; // current amount of entries bought in the raffle
        address player; // wallet address of the player
    }
    // every raffle has a sorted array of EntriesBought. Each element is created when calling
    // either buyEntry or giveBatchEntriesForFree
    mapping(uint256 => EntriesBought[]) public entriesList;

    // Main raffle data struct
    struct RaffleStruct {
        uint48 platformPercentage; // percentage of the funds raised that goes to the platform
        uint256 prizeNumber; // number (can be a percentage, an id, an amount, etc. depending on the competition)
        address winner; // address of thed winner of the raffle. Address(0) if no winner yet
        address seller; // address of the seller of the NFT
        uint256 randomNumber; // normalized (0-Entries array size) random number generated by the VRF
    }
    // The main structure is an array of raffles
    RaffleStruct[] public raffles;

    struct EntryInfoStruct {
        STATUS status; // status of the raffle. Can be created, accepted, ended, etc
        ENTRY_TYPE entryType;
        uint48 entriesLength; // to easy frontend, the length of the entries array is saved here
        uint128 amountRaised; // funds raised so far in wei
    }
    // The main structure is an array of raffles
    EntryInfoStruct[] public rafflesEntryInfo;

    // All the different status a rafVRFCoordinatorfle can have
    enum STATUS {
        CREATED, // the operator creates the raffle
        ACCEPTED, // the seller stakes the nft for the raffle
        EARLY_CASHOUT, // the seller wants to cashout early
        CANCELLED, // the operator cancels the raffle and transfer the remaining funds after 30 days passes
        CLOSING_REQUESTED, // the operator sets a winner
        ENDED, // the raffle is finished, and NFT and funds were transferred
        CANCEL_REQUESTED // operator asks to cancel the raffle. Players has 30 days to ask for a refund
    }

    enum ENTRY_TYPE {
        ONLY_DIRECTLY,
        ONLY_EXTERNAL_CONTRACT,
        MIXED
    }

    // The operator role is operated by a backend application
    bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR");
    // requested by Hamburger. Role for the buy method of the hamburger (only that contract)
    bytes32 public constant MINTERCONTRACT_ROLE = keccak256("MINTERCONTRACT");

    // address of the wallet controlled by the platform that will receive the platform fee
    address payable public destinationWallet =
        payable(0x52a032cF59eA274f9D745f29b6D514fe95Ba192D);

    constructor(
        address _vrfCoordinator,
        address _linkToken,
        bytes32 _keyHash,
        bool _mainetFee
    )
        VRFConsumerBase(
            _vrfCoordinator, // VRF Coordinator
            _linkToken // LINK Token
        )
    {
        _setupRole(OPERATOR_ROLE, 0x13503B622abC0bD30A7e9687057DF6E8c42Fb928);
        _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);

        keyHash = _keyHash;
        if (_mainetFee == true)
            fee = 2 * 10 ** 18; // in mainnet, the fee must be 2 LINK
        else fee = 0.1 * 10 ** 18; // 0.1 LINK In Rinkeby and Goerli
    }

    function callVRFAndGetRequestId() internal returns (bytes32 requestId) {
        require(
            LINK.balanceOf(address(this)) >= fee,
            "Not enough LINK - fill contract with faucet"
        );
        bytes32 result = requestRandomness(keyHash, fee);
        return result;
    }

    /// @dev this is the method that will be called by the smart contract to get a random number
    /// @param _id Id of the raffle
    /// @param _entriesSize length of the entries array of that raffle
    /// @param _requestId id generated by Chainlink
    function getRandomNumber(
        uint256 _id,
        uint256 _entriesSize,
        bytes32 _requestId
    ) internal {
        chainlinkRaffleInfo[_requestId] = RaffleInfo({
            id: _id,
            size: _entriesSize
        });
    }

    /// @dev Callback function used by VRF Coordinator. Is called by chainlink
    /// the random number generated is normalized to the size of the entries array, and an event is
    /// generated, that will be listened by the platform backend to be checked if corresponds to a
    /// member of the MW community, and if true will call transferNFTAndFunds
    /// @param requestId id generated previously (on method getRandomNumber by chainlink)
    /// @param randomness random number (huge) generated by chainlink
    function fulfillRandomness(
        bytes32 requestId,
        uint256 randomness
    ) internal override {
        // randomness is the actual random number. Now extract from the aux map the original param id of the call
        RaffleInfo memory raffleInfo = chainlinkRaffleInfo[requestId];
        // save the random number on the map with the original id as key
        uint256 normalizedRandomNumber = (randomness % raffleInfo.size) + 1;

        RandomResult memory result = RandomResult({
            randomNumber: randomness,
            nomalizedRandomNumber: normalizedRandomNumber
        });

        requests[raffleInfo.id] = result;

        // send the event with the original id and the random number
        emit RandomNumberCreated(
            raffleInfo.id,
            randomness,
            normalizedRandomNumber
        );

        transferPrizesAndFunds(raffleInfo.id, normalizedRandomNumber);
    }

    //////////////////////////////////////////////

    /// @param _desiredFundsInWeis the amount the seller would like to get from the raffle
    /// @param _collateralAddress The address of the NFT of the raffle
    /// @param _collateralId The id of the NFT (ERC721)
    /// @param _minimumFundsInWeis The mininum amount required for the raffle to set a winner
    /// @param _prices Array of prices and amount of entries the customer could purchase
    //   /// @param _commissionInBasicPoints commission for the platform, in basic points
    /// @notice Creates a raffle
    /// @dev creates a raffle struct and push it to the raffles array. Some data is stored in the funding data structure
    /// sends an event when finished
    /// @return raffleId
    function createRaffle(
        uint128 _desiredFundsInWeis,
        uint256 _prizeNumber,
        uint128 _minimumFundsInWeis,
        PriceStructure[] calldata _prices,
        uint48 _commissionInBasicPoints,
        ENTRY_TYPE _entryType
    ) external onlyRole(OPERATOR_ROLE) returns (uint256) {
        require(_commissionInBasicPoints <= 5000, "commission too high");

        RaffleStruct memory raffle = RaffleStruct({
            prizeNumber: _prizeNumber,
            winner: address(0),
            randomNumber: 0,
            seller: address(0),
            platformPercentage: _commissionInBasicPoints
        });
        raffles.push(raffle);

        saveEntryInfo(_entryType);

        uint256 idRaffle = raffles.length - 1;

        require(_prices.length > 0, "No prices");
        for (uint256 i = 0; i < _prices.length; i++) {
            require(_prices[i].numEntries > 0, "numEntries is 0");

            PriceStructure memory p = PriceStructure({
                id: idRaffle,
                numEntries: _prices[i].numEntries,
                price: _prices[i].price
            });
            pricesList[_prices[i].id] = p;
        }

        fundingList[idRaffle] = FundingStructure({
            minimumFundsInWeis: _minimumFundsInWeis,
            desiredFundsInWeis: _desiredFundsInWeis
        });

        emit RaffleCreated(idRaffle, _prizeNumber);

        // Initialize the entries list array, by adding a player and removing it
        EntriesBought memory entryBought = EntriesBought({
            player: msg.sender,
            currentEntriesLength: uint48(1)
        });
        entriesList[idRaffle].push(entryBought);
        delete entriesList[idRaffle][0];

        return idRaffle;
    }

    function saveEntryInfo(ENTRY_TYPE _entryType) internal {
        EntryInfoStruct memory entryInfo = EntryInfoStruct({
            status: STATUS.CREATED,
            amountRaised: 0,
            entriesLength: 0,
            entryType: _entryType
        });
        rafflesEntryInfo.push(entryInfo);
    }

    /// @param _raffleId Id of the raffle
    function stakeETH(uint256 _raffleId) external payable {
        EntryInfoStruct storage entryInfo = rafflesEntryInfo[_raffleId];
        RaffleStruct storage raffle = raffles[_raffleId];
        // Check if the raffle is already created
        require(entryInfo.status == STATUS.CREATED, "Raffle not CREATED");
        // check the amount staked is the correct
        require(raffle.prizeNumber == msg.value, "Prize not staked");

        entryInfo.status = STATUS.ACCEPTED;
        raffle.seller = msg.sender;
        emit RaffleStarted(_raffleId, msg.sender);
    }

    /// @dev callable by players. Depending on the number of entries assigned to the price structure the player buys (_id parameter)
    /// one or more entries will be assigned to the player.
    /// Also it is checked the maximum number of entries per user is not reached
    /// As the method is payable, in msg.value there will be the amount paid by the user
    /// @notice If the operator set requiredNFTs when creating the raffle, only the owners of nft on that collection can make a call to this method. This will be
    /// used for special raffles
    /// @param _raffleId: id of the raffle
    /// @param _id: id of the price structure
    function buyEntry(
        uint256 _raffleId,
        uint256 _id
    ) external payable /*nonReentrant*/ {
        EntryInfoStruct storage entryInfo = rafflesEntryInfo[_raffleId];
        if (entryInfo.status != STATUS.ACCEPTED)
            revert EntryNotAllowed("Not in ACCEPTED");
        // Not callable if the contract is only using hamburgers (150 gas)
        if (entryInfo.entryType == ENTRY_TYPE.ONLY_EXTERNAL_CONTRACT)
            revert EntryNotAllowed("Entry type not allowed");
        // Price checks
        if (_id == 0) revert EntryNotAllowed("howMany is 0");
        PriceStructure memory priceStruct = pricesList[_id];
        if (priceStruct.id != _raffleId)
            revert EntryNotAllowed("Id not in raffleId");
        uint48 numEntries = priceStruct.numEntries;
        if (numEntries == 0) revert EntryNotAllowed("Id not supported");
        if (msg.value != priceStruct.price)
            revert EntryNotAllowed("msg.value must be equal to the price");
        // save the entries onchain
        uint48 entriesLength = entryInfo.entriesLength;
        EntriesBought memory entryBought = EntriesBought({
            player: msg.sender,
            currentEntriesLength: uint48(entriesLength + numEntries)
        });
        entriesList[_raffleId].push(entryBought);
        // update raffle variables
        entryInfo.amountRaised += uint128(msg.value);
        entryInfo.entriesLength = entriesLength + numEntries;

        emit EntrySold(_raffleId, msg.sender, entryInfo.entriesLength, _id);
    }

    // The operator can add free entries to the raffle
    /// @param _raffleId Id of the raffle
    /// @param _freePlayers array of addresses corresponding to the wallet of the users that won a free entrie
    /// @dev only operator can make this call. Assigns a single entry per user, except if that user already reached the max limit of entries per user
    function giveBatchEntriesForFree(
        uint256 _raffleId,
        address[] memory _freePlayers
    ) external onlyRole(OPERATOR_ROLE) {
        EntryInfoStruct storage entryInfo = rafflesEntryInfo[_raffleId];
        require(
            entryInfo.status == STATUS.ACCEPTED,
            "Raffle is not in accepted"
        );

        uint256 freePlayersLength = _freePlayers.length;
        uint48 validPlayersCount = 0;
        for (uint256 i = 0; i < freePlayersLength; i++) {
            address entry = _freePlayers[i];
            // add a new element to the entriesBought array.
            // as this method only adds 1 entry per call, the amountbought is always 1
            EntriesBought memory entryBought = EntriesBought({
                player: entry,
                currentEntriesLength: uint48(entryInfo.entriesLength + i + 1)
            });
            entriesList[_raffleId].push(entryBought);
            ++validPlayersCount;
        }

        entryInfo.entriesLength = entryInfo.entriesLength + validPlayersCount;

        emit FreeEntry(
            _raffleId,
            _freePlayers,
            freePlayersLength,
            entryInfo.entriesLength
        );
    }

    // helper method to get the winner address of a raffle
    /// @param _raffleId Id of the raffle
    /// @param _normalizedRandomNumber Generated by chainlink
    /// @return the wallet that won the raffle
    /// @dev Uses a binary search on the sorted array to retreive the winner
    /// but if the winner candidate is blacklisted, loop through the left looking for
    /// a candidate not blacklisted
    function getWinnerAddressFromRandom(
        uint256 _raffleId,
        uint256 _normalizedRandomNumber
    ) public view returns (address) {
        uint256 position = findUpperBound(
            entriesList[_raffleId],
            _normalizedRandomNumber
        );

        address candidate = entriesList[_raffleId][position].player;
        // general case
        if (candidate != address(0)) return candidate;
        // special case. The user is blacklisted, so try next on the left until find a non-blacklisted
        else {
            bool ended = false;
            uint256 i = position;
            while (
                ended == false && entriesList[_raffleId][i].player == address(0)
            ) {
                if (i == 0) i = entriesList[_raffleId].length - 1;
                else i = i - 1;
                // we came to the beginning without finding a non blacklisted player
                if (i == position) ended == true;
            }
            require(!ended, "All users blacklisted");
            return entriesList[_raffleId][i].player;
        }
    }

    /// @param array sorted array of EntriesBought. CurrentEntriesLength is the numeric field used to sort
    /// @param element uint256 to find. Goes from 1 to entriesLength
    /// @dev based on openzeppelin code (v4.0), modified to use an array of EntriesBought
    /// Searches a sorted array and returns the first index that contains a value greater or equal to element.
    /// If no such index exists (i.e. all values in the array are strictly less than element), the array length is returned. Time complexity O(log n).
    /// array is expected to be sorted in ascending order, and to contain no repeated elements.
    /// https://docs.openzeppelin.com/contracts/3.x/api/utils#Arrays-findUpperBound-uint256---uint256-
    function findUpperBound(
        EntriesBought[] storage array,
        uint256 element
    ) internal view returns (uint256) {
        if (array.length == 0) {
            return 0;
        }

        uint256 low = 0;
        uint256 high = array.length;

        while (low < high) {
            uint256 mid = Math.average(low, high);

            // Note that mid will always be strictly less than high (i.e. it will be a valid array index)
            // because Math.average rounds down (it does integer division with truncation).
            if (array[mid].currentEntriesLength > element) {
                high = mid;
            } else {
                low = mid + 1;
            }
        }

        // At this point `low` is the exclusive upper bound. We will return the inclusive upper bound.
        if (low > 0 && array[low - 1].currentEntriesLength == element) {
            return low - 1;
        } else {
            return low;
        }
    }

    // The operator can call this method once they receive the event "RandomNumberCreated"
    // triggered by the VRF v1 consumer contract (RandomNumber.sol)
    /// @param _raffleId Id of the raffle
    /// @param _normalizedRandomNumber index of the array that contains the winner of the raffle. Generated by chainlink
    /// @notice it is the method that sets the winner and transfers funds and nft
    /// @dev called by Chainlink callback
    function transferPrizesAndFunds(
        uint256 _raffleId,
        uint256 _normalizedRandomNumber
    ) internal {
        RaffleStruct storage raffle = raffles[_raffleId];
        EntryInfoStruct storage entryInfo = rafflesEntryInfo[_raffleId];
        // Only when the raffle has been asked to be closed and the platform
        require(
            entryInfo.status == STATUS.EARLY_CASHOUT ||
                entryInfo.status == STATUS.CLOSING_REQUESTED,
            "Raffle in wrong status"
        );

        raffle.randomNumber = _normalizedRandomNumber;
        raffle.winner = getWinnerAddressFromRandom(
            _raffleId,
            _normalizedRandomNumber
        );
        entryInfo.status = STATUS.ENDED;

        // send the ETH to the winner
        (bool sentPrize, ) = raffle.winner.call{value: raffle.prizeNumber}("");
        require(sentPrize, "Failed to send Ether");

        uint256 amountForPlatform = (entryInfo.amountRaised *
            raffle.platformPercentage) / 10000;
        uint256 amountForSeller = entryInfo.amountRaised - amountForPlatform;
        // transfer amount (75%) to the seller.
        (bool sent, ) = raffle.seller.call{value: amountForSeller}("");
        require(sent, "Failed to send Ether");
        // transfer the amount to the platform
        (bool sent2, ) = destinationWallet.call{value: amountForPlatform}("");
        require(sent2, "Failed send Eth to MW");
        emit FeeTransferredToPlatform(_raffleId, amountForPlatform);

        emit RaffleEnded(
            _raffleId,
            raffle.winner,
            entryInfo.amountRaised,
            _normalizedRandomNumber
        );
    }

    function setCashOutActions(
        uint256 _raffleId
    ) internal returns (EntryInfoStruct memory) {
        RaffleStruct memory raffle = raffles[_raffleId];
        EntryInfoStruct storage entryInfo = rafflesEntryInfo[_raffleId];
        FundingStructure memory funding = fundingList[_raffleId];

        require(raffle.seller == msg.sender, "Not the seller");
        // Check if the raffle is already accepted
        require(
            entryInfo.status == STATUS.ACCEPTED,
            "Raffle not in accepted status"
        );
        require(
            entryInfo.amountRaised >= funding.minimumFundsInWeis,
            "Not enough funds raised"
        );

        entryInfo.status = STATUS.EARLY_CASHOUT;

        emit EarlyCashoutTriggered(_raffleId, entryInfo.amountRaised);

        return entryInfo;
    }

    // can be called by the seller at every moment once enough funds has been raised
    /// @param _raffleId Id of the raffle
    /// @notice the seller of the nft, if the minimum amount has been reached, can call an early cashout, finishing the raffle
    /// @dev it triggers Chainlink VRF1 consumer, and generates a random number that is normalized and checked that corresponds to a MW player
    function earlyCashOut(uint256 _raffleId) external {
     /*   EntryInfoStruct memory raffle = setWinnerActions(_raffleId);
        bytes32 requestId = callVRFAndGetRequestId();
        getRandomNumber(_raffleId, raffle.entriesLength, requestId);*/
    }

    function setWinnerActions(
        uint256 _raffleId
    ) internal returns (EntryInfoStruct memory) {
        EntryInfoStruct storage entryInfo = rafflesEntryInfo[_raffleId];
        // RaffleStruct storage raffle = raffles[_raffleId];
        FundingStructure storage funding = fundingList[_raffleId];
        // Check if the raffle is already accepted or is called again because early cashout failed
        require(entryInfo.status == STATUS.ACCEPTED, "Raffle in wrong status");
        require(
            entryInfo.amountRaised >= funding.minimumFundsInWeis,
            "Not enough funds raised"
        );

        require(
            funding.desiredFundsInWeis <= entryInfo.amountRaised,
            "Desired funds not raised"
        );
        entryInfo.status = STATUS.CLOSING_REQUESTED;

        emit SetWinnerTriggered(_raffleId, entryInfo.amountRaised);
        return entryInfo;
    }

    /// @param _raffleId Id of the raffle
    /// @notice the operator finish the raffle, if the desired funds has been reached
    /// @dev it triggers Chainlink VRF1 consumer, and generates a random number that is normalized and checked that corresponds to a MW player
    function setWinner(uint256 _raffleId) external onlyRole(OPERATOR_ROLE) {
        EntryInfoStruct memory raffle = setWinnerActions(_raffleId);
        // this call trigers the VRF v1 process from Chainlink

        bytes32 requestId = callVRFAndGetRequestId();
        getRandomNumber(_raffleId, raffle.entriesLength, requestId);
    }

    /// @param _newAddress new address of the platform
    /// @dev Change the wallet of the platform. The one that will receive the platform fee when the raffle is closed.
    /// Only the admin can change this
    function setDestinationAddress(
        address payable _newAddress
    ) external onlyRole(DEFAULT_ADMIN_ROLE) {
        destinationWallet = _newAddress;
    }

    /// @param _raffleId Id of the raffle
    /// @dev The operator can cancel the raffle. The NFT is sent back to the seller
    /// The raised funds are send to the destination wallet. The buyers will
    /// be refunded offchain in the metawin wallet
    function cancelRaffle(uint256 _raffleId) external onlyRole(OPERATOR_ROLE) {
        RaffleStruct storage raffle = raffles[_raffleId];
        EntryInfoStruct storage entryInfo = rafflesEntryInfo[_raffleId];
        // Dont cancel twice, or cancel an already ended raffle
        require(
            entryInfo.status != STATUS.ENDED &&
                entryInfo.status != STATUS.CANCELLED &&
                entryInfo.status != STATUS.EARLY_CASHOUT &&
                entryInfo.status != STATUS.CLOSING_REQUESTED &&
                entryInfo.status != STATUS.CANCEL_REQUESTED,
            "Wrong status"
        );

        // only if the raffle is in accepted status the ETH is staked and could have entries sold
        if (entryInfo.status == STATUS.ACCEPTED) {
            // transfer ETH to the owner
            (bool sentPrize, ) = raffle.seller.call{value: raffle.prizeNumber}(
                ""
            );
            require(sentPrize, "Failed to send Ether");
        }
        entryInfo.status = STATUS.CANCEL_REQUESTED;

        emit RaffleCancelled(_raffleId, entryInfo.amountRaised);
    }

    /// @param _raffleId Id of the raffle
    function transferRemainingFunds(
        uint256 _raffleId
    ) external onlyRole(OPERATOR_ROLE) {
        EntryInfoStruct storage entryInfo = rafflesEntryInfo[_raffleId];
        require(
            entryInfo.status == STATUS.CANCEL_REQUESTED ||
                entryInfo.status == STATUS.CANCELLED,
            "Wrong status"
        );

        entryInfo.status = STATUS.CANCELLED;

        (bool sent, ) = destinationWallet.call{value: entryInfo.amountRaised}(
            ""
        );
        require(sent, "Fail send Eth to MW");

        emit RemainingFundsTransferred(_raffleId, entryInfo.amountRaised);

        entryInfo.amountRaised = 0;
    }

    /// @param _raffleId Id of the raffle
    /// @return array of entries bougth of that particular raffle
    function getEntriesBought(
        uint256 _raffleId
    ) external view returns (EntriesBought[] memory) {
        return entriesList[_raffleId];
    }

    /// @dev for different reasons player entries should be void
    /// this has a cost in gas, but this makes cheaper in gas the callback from chainlink
    /// This method has to be called for every raffle of the blacklisted player
    /// @param _raffleId Id of the raffle
    /// @param entriesToCancel array that contains the index of the entries to cancel. 0 based
    /// @param _player player who owns the entry to be voided
    function cancelEntry(
        uint256 _raffleId,
        uint256[] calldata entriesToCancel,
        address _player
    ) external onlyRole(OPERATOR_ROLE) {
        uint256 totalEntriesBoughtCancelled = 0;
        for (uint256 i = 0; i < entriesToCancel.length; i++) {
            EntriesBought storage entry = entriesList[_raffleId][
                entriesToCancel[i] + 1
            ];

            require(entry.player == _player, "Entry did not belong to player");

            entry.player = address(0);

            uint256 previousTotalEntriesLength;
            if (entriesToCancel[i] == 0) previousTotalEntriesLength = 0;
            else
                previousTotalEntriesLength = entriesList[_raffleId][
                    entriesToCancel[i] /* - 1*/
                ].currentEntriesLength;
            totalEntriesBoughtCancelled +=
                entry.currentEntriesLength -
                previousTotalEntriesLength;
        }
        emit EntryCancelled(_raffleId, totalEntriesBoughtCancelled, _player);
    }

    // Requested by Valerio Di Napoli.
    /// @param _raffleId id of the raffle
    /// @param _amountOfEntries amount of entries. Must be lower than maxEntriesPerUser
    /// @param _player The address of the player
    /// @notice Called by other contract created by Valerio, that minted an NFT and after that call this method
    /// @dev add entries but they are free so no payable
    function createFreeEntriesFromExternalContract(
        uint256 _raffleId,
        uint48 _amountOfEntries,
        address _player
    ) external onlyRole(MINTERCONTRACT_ROLE) {
        // if can buy run this code.
        EntryInfoStruct storage entryInfo = rafflesEntryInfo[_raffleId];

        require(
            entryInfo.entryType == ENTRY_TYPE.ONLY_EXTERNAL_CONTRACT ||
                entryInfo.entryType == ENTRY_TYPE.MIXED,
            "Entry type not allowed"
        );

        EntriesBought memory entryBought = EntriesBought({
            player: _player,
            currentEntriesLength: entryInfo.entriesLength + _amountOfEntries
        });
        entriesList[_raffleId].push(entryBought);

        // update the field entriesLength.
        entryInfo.entriesLength += _amountOfEntries;

        address[] memory players = new address[](1);
        players[0] = _player;
        emit FreeEntry(
            _raffleId,
            players,
            _amountOfEntries,
            entryInfo.entriesLength
        );
    }

    function getRafflesEntryInfo(
        uint256 _raffleId
    ) public view returns (EntryInfoStruct memory) {
        return rafflesEntryInfo[_raffleId];
    }

    function playerIsBlacklisted(address _player) external pure returns (bool) {
        //  return blackListManager.isBlackListed(_player);
        return false;
    }

    function raffleNotInAcceptedState(
        uint256 _raffleId
    ) external view returns (bool) {
        EntryInfoStruct memory entryInfo = rafflesEntryInfo[_raffleId];
        return (entryInfo.status != STATUS.ACCEPTED);
    }

    function playerIsSeller(
        address _player,
        uint256 _raffleId
    ) external view returns (bool) {
        RaffleStruct memory raffle = raffles[_raffleId];
        return (raffle.seller == _player);
    }

    function playerReachedMaxEntries(
        address _player,
        uint256 _raffleId,
        uint256 _amountOfEntries
    ) external pure returns (bool) {
        return false;
    }

    /* Requested by Valerio Di Napoli.
    @param _player The address of the player    
    @param _raffleId id of the raffle
    @param _colection Address of the required collection, if any
    @param _tokenIdUsed Id of the token of the required collection the player says he has and want to use in the raffle
    @returns bool if the player can buy or not, and string with the cause of the rejection. "" if can buy
    @notice Method that returns if the user can or cannot buy entries because the player owns an nft in the case or required collections.
    */
    function playerHasRequiredNFTs(
        address _player,
        uint256 _raffleId,
        address _collection,
        uint256 _tokenIdUsed
    ) external pure returns (bool canBuy, string memory cause) {
        return (true, "");
    }
}

File 2 of 11 : Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/math/Math.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    enum Rounding {
        Down, // Toward negative infinity
        Up, // Toward infinity
        Zero // Toward zero
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a >= b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
     * with further edits by Uniswap Labs also under MIT license.
     */
    function mulDiv(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod0 := mul(x, y)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1);

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
            // See https://cs.stackexchange.com/q/138556/92363.

            // Does not overflow because the denominator cannot be zero at this stage in the function.
            uint256 twos = denominator & (~denominator + 1);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
            // in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(
        uint256 x,
        uint256 y,
        uint256 denominator,
        Rounding rounding
    ) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. It the number is not a perfect square, the value is rounded down.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`.
        // We also know that `k`, the position of the most significant bit, is such that `msb(a) = 2**k`.
        // This gives `2**k < a <= 2**(k+1)` → `2**(k/2) <= sqrt(a) < 2 ** (k/2+1)`.
        // Using an algorithm similar to the msb conmputation, we are able to compute `result = 2**(k/2)` which is a
        // good first aproximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1;
        uint256 x = a;
        if (x >> 128 > 0) {
            x >>= 128;
            result <<= 64;
        }
        if (x >> 64 > 0) {
            x >>= 64;
            result <<= 32;
        }
        if (x >> 32 > 0) {
            x >>= 32;
            result <<= 16;
        }
        if (x >> 16 > 0) {
            x >>= 16;
            result <<= 8;
        }
        if (x >> 8 > 0) {
            x >>= 8;
            result <<= 4;
        }
        if (x >> 4 > 0) {
            x >>= 4;
            result <<= 2;
        }
        if (x >> 2 > 0) {
            result <<= 1;
        }

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        uint256 result = sqrt(a);
        if (rounding == Rounding.Up && result * result < a) {
            result += 1;
        }
        return result;
    }
}

File 3 of 11 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

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

File 4 of 11 : ERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.0;

import "./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);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

File 5 of 11 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
    uint8 private constant _ADDRESS_LENGTH = 20;

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

        if (value == 0) {
            return "0";
        }
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return "0x00";
        }
        uint256 temp = value;
        uint256 length = 0;
        while (temp != 0) {
            length++;
            temp >>= 8;
        }
        return toHexString(value, length);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _HEX_SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
    }
}

File 6 of 11 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @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 7 of 11 : IAccessControl.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)

pragma solidity ^0.8.0;

/**
 * @dev External interface of AccessControl declared to support ERC165 detection.
 */
interface IAccessControl {
    /**
     * @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.
     *
     * _Available since v3.1._
     */
    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 `account`.
     */
    function renounceRole(bytes32 role, address account) external;
}

File 8 of 11 : AccessControl.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/AccessControl.sol)

pragma solidity ^0.8.0;

import "./IAccessControl.sol";
import "../utils/Context.sol";
import "../utils/Strings.sol";
import "../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:
 *
 * ```
 * 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}:
 *
 * ```
 * 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.
 */
abstract contract AccessControl is Context, IAccessControl, ERC165 {
    struct RoleData {
        mapping(address => bool) members;
        bytes32 adminRole;
    }

    mapping(bytes32 => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with a standardized message including the required role.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     *
     * _Available since v4.1._
     */
    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 override returns (bool) {
        return _roles[role].members[account];
    }

    /**
     * @dev Revert with a standard message if `_msgSender()` is missing `role`.
     * Overriding this function changes the behavior of the {onlyRole} modifier.
     *
     * Format of the revert message is described in {_checkRole}.
     *
     * _Available since v4.6._
     */
    function _checkRole(bytes32 role) internal view virtual {
        _checkRole(role, _msgSender());
    }

    /**
     * @dev Revert with a standard message if `account` is missing `role`.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     */
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!hasRole(role, account)) {
            revert(
                string(
                    abi.encodePacked(
                        "AccessControl: account ",
                        Strings.toHexString(uint160(account), 20),
                        " is missing role ",
                        Strings.toHexString(uint256(role), 32)
                    )
                )
            );
        }
    }

    /**
     * @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 override 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 override 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 override 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 `account`.
     *
     * May emit a {RoleRevoked} event.
     */
    function renounceRole(bytes32 role, address account) public virtual override {
        require(account == _msgSender(), "AccessControl: can only renounce roles for self");

        _revokeRole(role, account);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event. Note that unlike {grantRole}, this function doesn't perform any
     * checks on the calling account.
     *
     * May emit a {RoleGranted} event.
     *
     * [WARNING]
     * ====
     * This function should only be called from the constructor when setting
     * up the initial roles for the system.
     *
     * Using this function in any other way is effectively circumventing the admin
     * system imposed by {AccessControl}.
     * ====
     *
     * NOTE: This function is deprecated in favor of {_grantRole}.
     */
    function _setupRole(bytes32 role, address account) internal virtual {
        _grantRole(role, account);
    }

    /**
     * @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 Grants `role` to `account`.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleGranted} event.
     */
    function _grantRole(bytes32 role, address account) internal virtual {
        if (!hasRole(role, account)) {
            _roles[role].members[account] = true;
            emit RoleGranted(role, account, _msgSender());
        }
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleRevoked} event.
     */
    function _revokeRole(bytes32 role, address account) internal virtual {
        if (hasRole(role, account)) {
            _roles[role].members[account] = false;
            emit RoleRevoked(role, account, _msgSender());
        }
    }
}

File 9 of 11 : LinkTokenInterface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface LinkTokenInterface {
  function allowance(address owner, address spender) external view returns (uint256 remaining);

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

  function balanceOf(address owner) external view returns (uint256 balance);

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

  function decreaseApproval(address spender, uint256 addedValue) external returns (bool success);

  function increaseApproval(address spender, uint256 subtractedValue) external;

  function name() external view returns (string memory tokenName);

  function symbol() external view returns (string memory tokenSymbol);

  function totalSupply() external view returns (uint256 totalTokensIssued);

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

  function transferAndCall(
    address to,
    uint256 value,
    bytes calldata data
  ) external returns (bool success);

  function transferFrom(
    address from,
    address to,
    uint256 value
  ) external returns (bool success);
}

File 10 of 11 : VRFRequestIDBase.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract VRFRequestIDBase {
  /**
   * @notice returns the seed which is actually input to the VRF coordinator
   *
   * @dev To prevent repetition of VRF output due to repetition of the
   * @dev user-supplied seed, that seed is combined in a hash with the
   * @dev user-specific nonce, and the address of the consuming contract. The
   * @dev risk of repetition is mostly mitigated by inclusion of a blockhash in
   * @dev the final seed, but the nonce does protect against repetition in
   * @dev requests which are included in a single block.
   *
   * @param _userSeed VRF seed input provided by user
   * @param _requester Address of the requesting contract
   * @param _nonce User-specific nonce at the time of the request
   */
  function makeVRFInputSeed(
    bytes32 _keyHash,
    uint256 _userSeed,
    address _requester,
    uint256 _nonce
  ) internal pure returns (uint256) {
    return uint256(keccak256(abi.encode(_keyHash, _userSeed, _requester, _nonce)));
  }

  /**
   * @notice Returns the id for this request
   * @param _keyHash The serviceAgreement ID to be used for this request
   * @param _vRFInputSeed The seed to be passed directly to the VRF
   * @return The id for this request
   *
   * @dev Note that _vRFInputSeed is not the seed passed by the consuming
   * @dev contract, but the one generated by makeVRFInputSeed
   */
  function makeRequestId(bytes32 _keyHash, uint256 _vRFInputSeed) internal pure returns (bytes32) {
    return keccak256(abi.encodePacked(_keyHash, _vRFInputSeed));
  }
}

File 11 of 11 : VRFConsumerBase.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./interfaces/LinkTokenInterface.sol";

import "./VRFRequestIDBase.sol";

/** ****************************************************************************
 * @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.
 * *****************************************************************************
 * @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, _link) 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), and have told you the minimum LINK
 * @dev price for VRF service. Make sure your contract has sufficient LINK, and
 * @dev call requestRandomness(keyHash, fee, seed), where seed is the input you
 * @dev want to generate randomness from.
 *
 * @dev Once the VRFCoordinator has received and validated the oracle's response
 * @dev to your request, it will call your contract's fulfillRandomness method.
 *
 * @dev The randomness argument to fulfillRandomness is the actual random value
 * @dev generated from your seed.
 *
 * @dev The requestId argument is generated from the keyHash and the seed by
 * @dev makeRequestId(keyHash, seed). If your contract could have concurrent
 * @dev requests open, you can use the requestId to track which seed is
 * @dev associated with which randomness. See VRFRequestIDBase.sol for more
 * @dev details. (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. (Which is critical to making unpredictable randomness! See the
 * @dev next section.)
 *
 * *****************************************************************************
 * @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 ultimate input to the VRF is mixed with the block hash of the
 * @dev block in which the request is made, user-provided seeds have no impact
 * @dev on its economic security properties. They are only included for API
 * @dev compatability with previous versions of this contract.
 *
 * @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.
 */
abstract contract VRFConsumerBase is VRFRequestIDBase {
  /**
   * @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 VRFConsumerBase 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 randomness the VRF output
   */
  function fulfillRandomness(bytes32 requestId, uint256 randomness) internal virtual;

  /**
   * @dev In order to keep backwards compatibility we have kept the user
   * seed field around. We remove the use of it because given that the blockhash
   * enters later, it overrides whatever randomness the used seed provides.
   * Given that it adds no security, and can easily lead to misunderstandings,
   * we have removed it from usage and can now provide a simpler API.
   */
  uint256 private constant USER_SEED_PLACEHOLDER = 0;

  /**
   * @notice requestRandomness initiates a request for VRF output given _seed
   *
   * @dev The fulfillRandomness method receives the output, once it's provided
   * @dev by the Oracle, and verified by the vrfCoordinator.
   *
   * @dev The _keyHash must already be registered with the VRFCoordinator, and
   * @dev the _fee must exceed the fee specified during registration of the
   * @dev _keyHash.
   *
   * @dev The _seed parameter is vestigial, and is kept only for API
   * @dev compatibility with older versions. It can't *hurt* to mix in some of
   * @dev your own randomness, here, but it's not necessary because the VRF
   * @dev oracle will mix the hash of the block containing your request into the
   * @dev VRF seed it ultimately uses.
   *
   * @param _keyHash ID of public key against which randomness is generated
   * @param _fee The amount of LINK to send with the request
   *
   * @return requestId unique ID for this request
   *
   * @dev The returned requestId can be used to distinguish responses to
   * @dev concurrent requests. It is passed as the first argument to
   * @dev fulfillRandomness.
   */
  function requestRandomness(bytes32 _keyHash, uint256 _fee) internal returns (bytes32 requestId) {
    LINK.transferAndCall(vrfCoordinator, _fee, abi.encode(_keyHash, USER_SEED_PLACEHOLDER));
    // This is the seed passed to VRFCoordinator. The oracle will mix this with
    // the hash of the block containing this request to obtain the seed/input
    // which is finally passed to the VRF cryptographic machinery.
    uint256 vRFSeed = makeVRFInputSeed(_keyHash, USER_SEED_PLACEHOLDER, address(this), nonces[_keyHash]);
    // nonces[_keyHash] must stay in sync with
    // VRFCoordinator.nonces[_keyHash][this], which was incremented by the above
    // successful LINK.transferAndCall (in VRFCoordinator.randomnessRequest).
    // This provides protection against the user repeating their input seed,
    // which would result in a predictable/duplicate output, if multiple such
    // requests appeared in the same block.
    nonces[_keyHash] = nonces[_keyHash] + 1;
    return makeRequestId(_keyHash, vRFSeed);
  }

  LinkTokenInterface internal immutable LINK;
  address private immutable vrfCoordinator;

  // Nonces for each VRF key from which randomness has been requested.
  //
  // Must stay in sync with VRFCoordinator[_keyHash][this]
  mapping(bytes32 => uint256) /* keyHash */ /* nonce */
    private nonces;

  /**
   * @param _vrfCoordinator address of VRFCoordinator contract
   * @param _link address of LINK token contract
   *
   * @dev https://docs.chain.link/docs/link-token-contracts
   */
  constructor(address _vrfCoordinator, address _link) {
    vrfCoordinator = _vrfCoordinator;
    LINK = LinkTokenInterface(_link);
  }

  // rawFulfillRandomness is called by VRFCoordinator when it receives a valid VRF
  // proof. rawFulfillRandomness then calls fulfillRandomness, after validating
  // the origin of the call
  function rawFulfillRandomness(bytes32 requestId, uint256 randomness) external {
    require(msg.sender == vrfCoordinator, "Only VRFCoordinator can fulfill");
    fulfillRandomness(requestId, randomness);
  }
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_vrfCoordinator","type":"address"},{"internalType":"address","name":"_linkToken","type":"address"},{"internalType":"bytes32","name":"_keyHash","type":"bytes32"},{"internalType":"bool","name":"_mainetFee","type":"bool"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"string","name":"errorType","type":"string"}],"name":"EntryNotAllowed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountRaised","type":"uint256"}],"name":"EarlyCashoutTriggered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfEntriesCanceled","type":"uint256"},{"indexed":false,"internalType":"address","name":"player","type":"address"}],"name":"EntryCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":true,"internalType":"address","name":"buyer","type":"address"},{"indexed":false,"internalType":"uint256","name":"currentSize","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"priceStructureId","type":"uint256"}],"name":"EntrySold","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountTransferred","type":"uint256"}],"name":"FeeTransferredToPlatform","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":false,"internalType":"address[]","name":"buyer","type":"address[]"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"currentSize","type":"uint256"}],"name":"FreeEntry","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountRaised","type":"uint256"}],"name":"RaffleCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"nftId","type":"uint256"}],"name":"RaffleCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":true,"internalType":"address","name":"winner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountRaised","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"randomNumber","type":"uint256"}],"name":"RaffleEnded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":true,"internalType":"address","name":"seller","type":"address"}],"name":"RaffleStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"idFromMetawin","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"randomNumber","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"normalizedRandomNumber","type":"uint256"}],"name":"RandomNumberCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountInWeis","type":"uint256"},{"indexed":true,"internalType":"address","name":"player","type":"address"}],"name":"Refund","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountInWeis","type":"uint256"}],"name":"RemainingFundsTransferred","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":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountRaised","type":"uint256"}],"name":"SetWinnerTriggered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newStatus","type":"uint256"}],"name":"StatusChangedInEmergency","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINTERCONTRACT_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OPERATOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_raffleId","type":"uint256"},{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"buyEntry","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_raffleId","type":"uint256"},{"internalType":"uint256[]","name":"entriesToCancel","type":"uint256[]"},{"internalType":"address","name":"_player","type":"address"}],"name":"cancelEntry","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_raffleId","type":"uint256"}],"name":"cancelRaffle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"chainlinkRaffleInfo","outputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"size","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_raffleId","type":"uint256"},{"internalType":"uint48","name":"_amountOfEntries","type":"uint48"},{"internalType":"address","name":"_player","type":"address"}],"name":"createFreeEntriesFromExternalContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"_desiredFundsInWeis","type":"uint128"},{"internalType":"uint256","name":"_prizeNumber","type":"uint256"},{"internalType":"uint128","name":"_minimumFundsInWeis","type":"uint128"},{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint48","name":"numEntries","type":"uint48"},{"internalType":"uint256","name":"price","type":"uint256"}],"internalType":"struct ETHFixedLean.PriceStructure[]","name":"_prices","type":"tuple[]"},{"internalType":"uint48","name":"_commissionInBasicPoints","type":"uint48"},{"internalType":"enum ETHFixedLean.ENTRY_TYPE","name":"_entryType","type":"uint8"}],"name":"createRaffle","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"destinationWallet","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_raffleId","type":"uint256"}],"name":"earlyCashOut","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"entriesList","outputs":[{"internalType":"uint48","name":"currentEntriesLength","type":"uint48"},{"internalType":"address","name":"player","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"fundingList","outputs":[{"internalType":"uint128","name":"minimumFundsInWeis","type":"uint128"},{"internalType":"uint128","name":"desiredFundsInWeis","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_raffleId","type":"uint256"}],"name":"getEntriesBought","outputs":[{"components":[{"internalType":"uint48","name":"currentEntriesLength","type":"uint48"},{"internalType":"address","name":"player","type":"address"}],"internalType":"struct ETHFixedLean.EntriesBought[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_raffleId","type":"uint256"}],"name":"getRafflesEntryInfo","outputs":[{"components":[{"internalType":"enum ETHFixedLean.STATUS","name":"status","type":"uint8"},{"internalType":"enum ETHFixedLean.ENTRY_TYPE","name":"entryType","type":"uint8"},{"internalType":"uint48","name":"entriesLength","type":"uint48"},{"internalType":"uint128","name":"amountRaised","type":"uint128"}],"internalType":"struct ETHFixedLean.EntryInfoStruct","name":"","type":"tuple"}],"stateMutability":"view","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":"_raffleId","type":"uint256"},{"internalType":"uint256","name":"_normalizedRandomNumber","type":"uint256"}],"name":"getWinnerAddressFromRandom","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_raffleId","type":"uint256"},{"internalType":"address[]","name":"_freePlayers","type":"address[]"}],"name":"giveBatchEntriesForFree","outputs":[],"stateMutability":"nonpayable","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":"address","name":"_player","type":"address"},{"internalType":"uint256","name":"_raffleId","type":"uint256"},{"internalType":"address","name":"_collection","type":"address"},{"internalType":"uint256","name":"_tokenIdUsed","type":"uint256"}],"name":"playerHasRequiredNFTs","outputs":[{"internalType":"bool","name":"canBuy","type":"bool"},{"internalType":"string","name":"cause","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_player","type":"address"}],"name":"playerIsBlacklisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_player","type":"address"},{"internalType":"uint256","name":"_raffleId","type":"uint256"}],"name":"playerIsSeller","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_player","type":"address"},{"internalType":"uint256","name":"_raffleId","type":"uint256"},{"internalType":"uint256","name":"_amountOfEntries","type":"uint256"}],"name":"playerReachedMaxEntries","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"pricesList","outputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint48","name":"numEntries","type":"uint48"},{"internalType":"uint256","name":"price","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_raffleId","type":"uint256"}],"name":"raffleNotInAcceptedState","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"raffles","outputs":[{"internalType":"uint48","name":"platformPercentage","type":"uint48"},{"internalType":"uint256","name":"prizeNumber","type":"uint256"},{"internalType":"address","name":"winner","type":"address"},{"internalType":"address","name":"seller","type":"address"},{"internalType":"uint256","name":"randomNumber","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rafflesEntryInfo","outputs":[{"internalType":"enum ETHFixedLean.STATUS","name":"status","type":"uint8"},{"internalType":"enum ETHFixedLean.ENTRY_TYPE","name":"entryType","type":"uint8"},{"internalType":"uint48","name":"entriesLength","type":"uint48"},{"internalType":"uint128","name":"amountRaised","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"requestId","type":"bytes32"},{"internalType":"uint256","name":"randomness","type":"uint256"}],"name":"rawFulfillRandomness","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"requests","outputs":[{"internalType":"uint256","name":"randomNumber","type":"uint256"},{"internalType":"uint256","name":"nomalizedRandomNumber","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"_newAddress","type":"address"}],"name":"setDestinationAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_raffleId","type":"uint256"}],"name":"setWinner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_raffleId","type":"uint256"}],"name":"stakeETH","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":[{"internalType":"uint256","name":"_raffleId","type":"uint256"}],"name":"transferRemainingFunds","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60c0604052600b80546001600160a01b0319167352a032cf59ea274f9d745f29b6d514fe95ba192d1790553480156200003757600080fd5b50604051620041d7380380620041d78339810160408190526200005a91620001c8565b6001600160601b0319606085811b821660a05284901b16608052620000b47f523a704056dcd17bcf83bed8b68c59416dac1119be77755efe3bde0a64e46e0c7313503b622abc0bd30a7e9687057df6e8c42fb928620000fb565b620000c1600033620000fb565b600282905560018115151415620000e457671bc16d674ec80000600355620000f1565b67016345785d8a00006003555b5050505062000220565b6200010782826200010b565b5050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff1662000107576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055620001673390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b80516001600160a01b0381168114620001c357600080fd5b919050565b60008060008060808587031215620001de578384fd5b620001e985620001ab565b9350620001f960208601620001ab565b9250604085015191506060850151801515811462000215578182fd5b939692955090935050565b60805160601c60a05160601c613f7d6200025a600039600081816122070152612eca0152600081816129700152612e9b0152613f7d6000f3fe60806040526004361061021a5760003560e01c806353b7a59b1161012357806393a75d02116100ab578063d649214c1161006f578063d649214c14610789578063ddba6e6b146107a9578063eb99038c1461080f578063f369145514610833578063f5b541a61461085357600080fd5b806393a75d02146106c357806394985ddd146106f0578063a217fddf14610710578063babdf60b14610725578063d547741f1461076957600080fd5b80636ecc20da116100f25780636ecc20da146106085780637c903fc01461061b5780637fa4cacb1461064f57806381d12c581461066f57806391d14854146106a357600080fd5b806353b7a59b146105335780635d4bc0ce1461056b5780635fba3171146105c85780636371ba0d146105e857600080fd5b8063248a9ca3116101a657806336568abe1161017557806336568abe14610478578063365e36581461049857806336734e34146104c55780633a3956c2146104e55780634239a50c1461051557600080fd5b8063248a9ca3146103b15780632a596800146103ef5780632f2ff15d14610438578063317f30591461045857600080fd5b80630b148ff0116101ed5780630b148ff01461031b5780630df716021461033d5780631e6cd3951461035d5780631fe968571461037d578063236854961461039e57600080fd5b8063013805c51461021f57806301ffc9a71461026a578063039be5581461029a578063043a1c9a146102fb575b600080fd5b34801561022b57600080fd5b5061023f61023a36600461375f565b610875565b6040805165ffffffffffff90931683526001600160a01b039091166020830152015b60405180910390f35b34801561027657600080fd5b5061028a610285366004613780565b6108bd565b6040519015158152602001610261565b3480156102a657600080fd5b506102db6102b5366004613718565b6007602052600090815260409020546001600160801b0380821691600160801b90041682565b604080516001600160801b03938416815292909116602083015201610261565b34801561030757600080fd5b5061028a610316366004613652565b6108f4565b34801561032757600080fd5b5061033b6103363660046139dd565b61098d565b005b34801561034957600080fd5b5061033b610358366004613718565b610c49565b34801561036957600080fd5b5061028a610378366004613718565b610cbe565b34801561038957600080fd5b5061028a610398366004613636565b50600090565b61033b6103ac36600461375f565b610de9565b3480156103bd57600080fd5b506103e16103cc366004613718565b60009081526020819052604090206001015490565b604051908152602001610261565b3480156103fb57600080fd5b5061042361040a366004613718565b6005602052600090815260409020805460019091015482565b60408051928352602083019190915201610261565b34801561044457600080fd5b5061033b610453366004613730565b6111b4565b34801561046457600080fd5b5061033b610473366004613718565b6111de565b34801561048457600080fd5b5061033b610493366004613730565b6113ca565b3480156104a457600080fd5b506104b86104b3366004613718565b611448565b6040516102619190613bd1565b3480156104d157600080fd5b5061033b6104e036600461387d565b6114d6565b3480156104f157600080fd5b50610505610500366004613718565b61171f565b6040516102619493929190613c4c565b34801561052157600080fd5b5061033b610530366004613718565b50565b34801561053f57600080fd5b50600b54610553906001600160a01b031681565b6040516001600160a01b039091168152602001610261565b34801561057757600080fd5b5061058b610586366004613718565b61176b565b6040805165ffffffffffff909616865260208601949094526001600160a01b0392831693850193909352166060830152608082015260a001610261565b3480156105d457600080fd5b5061033b6105e3366004613718565b6117c2565b3480156105f457600080fd5b506103e16106033660046137a8565b611a61565b61033b610616366004613718565b611f17565b34801561062757600080fd5b506103e17fde5ee446972f4e39ab62c03aa34b2096680a875c3fdb3eb2f947cbb93341c05881565b34801561065b57600080fd5b5061033b61066a366004613636565b612079565b34801561067b57600080fd5b5061042361068a366004613718565b6004602052600090815260409020805460019091015482565b3480156106af57600080fd5b5061028a6106be366004613730565b6120a7565b3480156106cf57600080fd5b506106e36106de366004613718565b6120d0565b6040516102619190613cce565b3480156106fc57600080fd5b5061033b61070b36600461375f565b6121fc565b34801561071c57600080fd5b506103e1600081565b34801561073157600080fd5b5061075b61074036600461367d565b60408051602081019091526000815260019094509492505050565b604051610261929190613c31565b34801561077557600080fd5b5061033b610784366004613730565b61227e565b34801561079557600080fd5b5061033b6107a4366004613950565b6122a3565b3480156107b557600080fd5b506107ed6107c4366004613718565b600660205260009081526040902080546001820154600290920154909165ffffffffffff169083565b6040805193845265ffffffffffff909216602084015290820152606001610261565b34801561081b57600080fd5b5061028a61082a3660046136c4565b60009392505050565b34801561083f57600080fd5b5061055361084e36600461375f565b6124c5565b34801561085f57600080fd5b506103e1600080516020613f2883398151915281565b6008602052816000526040600020818154811061089157600080fd5b60009182526020909120015465ffffffffffff81169250600160301b90046001600160a01b0316905082565b60006001600160e01b03198216637965db0b60e01b14806108ee57506301ffc9a760e01b6001600160e01b03198316145b92915050565b6000806009838154811061091857634e487b7160e01b600052603260045260246000fd5b60009182526020918290206040805160a0810182526005909302909101805465ffffffffffff16835260018101549383019390935260028301546001600160a01b0390811691830191909152600383015481166060830181905260049093015460809092019190915285161491505092915050565b7fde5ee446972f4e39ab62c03aa34b2096680a875c3fdb3eb2f947cbb93341c0586109b78161266b565b6000600a85815481106109da57634e487b7160e01b600052603260045260246000fd5b6000918252602090912001905060018154610100900460ff166002811115610a1257634e487b7160e01b600052602160045260246000fd5b1480610a46575060028154610100900460ff166002811115610a4457634e487b7160e01b600052602160045260246000fd5b145b610a905760405162461bcd60e51b8152602060048201526016602482015275115b9d1c9e481d1e5c19481b9bdd08185b1b1bddd95960521b60448201526064015b60405180910390fd5b60006040518060400160405280868460000160029054906101000a900465ffffffffffff16610abf9190613d62565b65ffffffffffff90811682526001600160a01b0380881660209384015260008a8152600884526040812080546001810182559082529084902085519101805494860151909216600160301b026001600160d01b03199094169083161792909217909155835491925086918491600291610b4091859162010000900416613d62565b92506101000a81548165ffffffffffff021916908365ffffffffffff1602179055506000600167ffffffffffffffff811115610b8c57634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015610bb5578160200160208202803683370190505b5090508481600081518110610bda57634e487b7160e01b600052603260045260246000fd5b6001600160a01b0390921660209283029190910190910152825460405188917f4da4f5fab0816c65315b6f5d15f879f96b98661133d7b3787788f291367604fb91610c389185918b9165ffffffffffff620100009091041690613b9f565b60405180910390a250505050505050565b600080516020613f28833981519152610c618161266b565b6000610c6c83612675565b90506000610c7861294c565b9050610cb884836040015165ffffffffffff1683604080518082018252938452602080850193845260009283526005905290209151825551600190910155565b50505050565b600080600a8381548110610ce257634e487b7160e01b600052603260045260246000fd5b60009182526020909120604080516080810190915291018054829060ff166006811115610d1f57634e487b7160e01b600052602160045260246000fd5b6006811115610d3e57634e487b7160e01b600052602160045260246000fd5b81528154602090910190610100900460ff166002811115610d6f57634e487b7160e01b600052602160045260246000fd5b6002811115610d8e57634e487b7160e01b600052602160045260246000fd5b8152905462010000810465ffffffffffff166020830152600160401b90046001600160801b03166040909101529050600181516006811115610de057634e487b7160e01b600052602160045260246000fd5b14159392505050565b6000600a8381548110610e0c57634e487b7160e01b600052603260045260246000fd5b600091825260209091200190506001815460ff166006811115610e3f57634e487b7160e01b600052602160045260246000fd5b14610e7f5760405163efeb42cf60e01b815260206004820152600f60248201526e139bdd081a5b881050d0d154151151608a1b6044820152606401610a87565b60018154610100900460ff166002811115610eaa57634e487b7160e01b600052602160045260246000fd5b1415610ef25760405163efeb42cf60e01b8152602060048201526016602482015275115b9d1c9e481d1e5c19481b9bdd08185b1b1bddd95960521b6044820152606401610a87565b81610f2f5760405163efeb42cf60e01b815260206004820152600c60248201526b0686f774d616e7920697320360a41b6044820152606401610a87565b60008281526006602090815260409182902082516060810184528154808252600183015465ffffffffffff1693820193909352600290910154928101929092528414610fb35760405163efeb42cf60e01b81526020600482015260126024820152711259081b9bdd081a5b881c9859999b19525960721b6044820152606401610a87565b602081015165ffffffffffff81166110015760405163efeb42cf60e01b815260206004820152601060248201526f1259081b9bdd081cdd5c1c1bdc9d195960821b6044820152606401610a87565b816040015134146110615760405163efeb42cf60e01b8152602060048201526024808201527f6d73672e76616c7565206d75737420626520657175616c20746f2074686520706044820152637269636560e01b6064820152608401610a87565b8254604080518082019091526201000090910465ffffffffffff16906000908061108b8585613d62565b65ffffffffffff90811682523360209283015260008a8152600880845260408220805460018101825590835291849020855192018054948601516001600160a01b0316600160301b026001600160d01b03199095169290931691909117929092179055865491925034918791906111149084906001600160801b03600160401b90910416613d1f565b92506101000a8154816001600160801b0302191690836001600160801b0316021790555082826111449190613d62565b855467ffffffffffff000019166201000065ffffffffffff9283168102919091178088556040805192909104909216815260208101889052339189917fd746af8dc82f9bed98cea0fe0264eb1c3d2e5f7bcc77fc5efb429c79df407887910160405180910390a350505050505050565b6000828152602081905260409020600101546111cf8161266b565b6111d98383612a5c565b505050565b600080516020613f288339815191526111f68161266b565b6000600a838154811061121957634e487b7160e01b600052603260045260246000fd5b600091825260209091200190506006815460ff16600681111561124c57634e487b7160e01b600052602160045260246000fd5b148061127b57506003815460ff16600681111561127957634e487b7160e01b600052602160045260246000fd5b145b6112b65760405162461bcd60e51b815260206004820152600c60248201526b57726f6e672073746174757360a01b6044820152606401610a87565b805460ff1916600317808255600b546040516000926001600160a01b03909216916001600160801b03600160401b90910416908381818185875af1925050503d8060008114611321576040519150601f19603f3d011682016040523d82523d6000602084013e611326565b606091505b505090508061136d5760405162461bcd60e51b81526020600482015260136024820152724661696c2073656e642045746820746f204d5760681b6044820152606401610a87565b8154604051600160401b9091046001600160801b0316815284907fcdef6558dae40f2699846eedf449462daab85b1224ad7f077569ba91aaa949259060200160405180910390a2508054600160401b600160c01b03191690555050565b6001600160a01b038116331461143a5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401610a87565b6114448282612ae0565b5050565b606060086000838152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b828210156114cb576000848152602090819020604080518082019091529084015465ffffffffffff81168252600160301b90046001600160a01b03168183015282526001909201910161147d565b505050509050919050565b600080516020613f288339815191526114ee8161266b565b6000600a848154811061151157634e487b7160e01b600052603260045260246000fd5b600091825260209091200190506001815460ff16600681111561154457634e487b7160e01b600052602160045260246000fd5b146115915760405162461bcd60e51b815260206004820152601960248201527f526166666c65206973206e6f7420696e206163636570746564000000000000006044820152606401610a87565b82516000805b828110156116935760008682815181106115c157634e487b7160e01b600052603260045260246000fd5b6020026020010151905060006040518060400160405280848860000160029054906101000a900465ffffffffffff1665ffffffffffff166116029190613d4a565b61160d906001613d4a565b65ffffffffffff90811682526001600160a01b0380861660209384015260008d8152600884526040812080546001810182559082529084902085519101805494860151909216600160301b026001600160d01b0319909416921691909117919091179055905061167c84613e80565b93505050808061168b90613e65565b915050611597565b5082546116af90829062010000900465ffffffffffff16613d62565b835467ffffffffffff000019166201000065ffffffffffff92831681029190911780865560405189937f4da4f5fab0816c65315b6f5d15f879f96b98661133d7b3787788f291367604fb9361170f938b9389939290910490911690613b6e565b60405180910390a2505050505050565b600a818154811061172f57600080fd5b60009182526020909120015460ff80821692506101008204169062010000810465ffffffffffff1690600160401b90046001600160801b031684565b6009818154811061177b57600080fd5b60009182526020909120600590910201805460018201546002830154600384015460049094015465ffffffffffff909316945090926001600160a01b039182169291169085565b600080516020613f288339815191526117da8161266b565b6000600983815481106117fd57634e487b7160e01b600052603260045260246000fd5b906000526020600020906005020190506000600a848154811061183057634e487b7160e01b600052603260045260246000fd5b600091825260209091200190506005815460ff16600681111561186357634e487b7160e01b600052602160045260246000fd5b1415801561189557506003815460ff16600681111561189257634e487b7160e01b600052602160045260246000fd5b14155b80156118c557506002815460ff1660068111156118c257634e487b7160e01b600052602160045260246000fd5b14155b80156118f557506004815460ff1660068111156118f257634e487b7160e01b600052602160045260246000fd5b14155b801561192557506006815460ff16600681111561192257634e487b7160e01b600052602160045260246000fd5b14155b6119605760405162461bcd60e51b815260206004820152600c60248201526b57726f6e672073746174757360a01b6044820152606401610a87565b6001815460ff16600681111561198657634e487b7160e01b600052602160045260246000fd5b1415611a0757600382015460018301546040516000926001600160a01b031691908381818185875af1925050503d80600081146119df576040519150601f19603f3d011682016040523d82523d6000602084013e6119e4565b606091505b5050905080611a055760405162461bcd60e51b8152600401610a8790613ca0565b505b805460ff19166006178082556040516001600160801b03600160401b90920491909116815284907fd512a34b0f0618078770fcd85d974df1ab46a7882e8b3d45aa91764f4961aed29060200160405180910390a250505050565b6000600080516020613f28833981519152611a7b8161266b565b6113888465ffffffffffff161115611acb5760405162461bcd60e51b81526020600482015260136024820152720c6dedadad2e6e6d2dedc40e8dede40d0d2ced606b1b6044820152606401610a87565b6040805160a08101825265ffffffffffff8681168252602082018b81526000938301848152606084018581526080850186815260098054600181018255975285517f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af6005909802978801805465ffffffffffff1916919096161790945591517f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7b0860155517f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7b1850180546001600160a01b03199081166001600160a01b039384161790915591517f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7b2860180549093169116179055517f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7b390920191909155611c1084612b45565b600954600090611c2290600190613e0b565b905086611c5d5760405162461bcd60e51b81526020600482015260096024820152684e6f2070726963657360b81b6044820152606401610a87565b60005b87811015611df6576000898983818110611c8a57634e487b7160e01b600052603260045260246000fd5b9050606002016020016020810190611ca29190613a1c565b65ffffffffffff1611611ce95760405162461bcd60e51b815260206004820152600f60248201526e06e756d456e7472696573206973203608c1b6044820152606401610a87565b600060405180606001604052808481526020018b8b85818110611d1c57634e487b7160e01b600052603260045260246000fd5b9050606002016020016020810190611d349190613a1c565b65ffffffffffff1681526020018b8b85818110611d6157634e487b7160e01b600052603260045260246000fd5b90506060020160400135815250905080600660008c8c86818110611d9557634e487b7160e01b600052603260045260246000fd5b60600291909101358252506020808201929092526040908101600020835181559183015160018301805465ffffffffffff191665ffffffffffff90921691909117905591909101516002909101555080611dee81613e65565b915050611c60565b506040805180820182526001600160801b03808c1682528d8116602080840191825260008681526007909152848120935191518316600160801b02919092161790915590518b9183917ff6f5afeb49bc62176d1efaa06a1753999cc29bf378f1004ea916f37f41d7638a9190a360408051808201825260018082523360208084019182526000868152600882529485208054938401815580865290852084519301805492516001600160a01b0316600160301b026001600160d01b031990931665ffffffffffff949094169390931791909117909155838352805491929091611eef57634e487b7160e01b600052603260045260246000fd5b600091825260209091200180546001600160d01b0319169055509a9950505050505050505050565b6000600a8281548110611f3a57634e487b7160e01b600052603260045260246000fd5b906000526020600020019050600060098381548110611f6957634e487b7160e01b600052603260045260246000fd5b6000918252602082206005909102019150825460ff166006811115611f9e57634e487b7160e01b600052602160045260246000fd5b14611fe05760405162461bcd60e51b8152602060048201526012602482015271149859999b19481b9bdd0810d4915055115160721b6044820152606401610a87565b348160010154146120265760405162461bcd60e51b815260206004820152601060248201526f141c9a5e99481b9bdd081cdd185ad95960821b6044820152606401610a87565b815460ff19166001178255600381018054336001600160a01b0319909116811790915560405184907f8bb509eedfd1c4847b0a8a2b4493cf2ebb9970dc367e477cd2a8523e212dc1db90600090a3505050565b60006120848161266b565b50600b80546001600160a01b0319166001600160a01b0392909216919091179055565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b6120fc604080516080810190915280600081526020016000815260006020820181905260409091015290565b600a828154811061211d57634e487b7160e01b600052603260045260246000fd5b60009182526020909120604080516080810190915291018054829060ff16600681111561215a57634e487b7160e01b600052602160045260246000fd5b600681111561217957634e487b7160e01b600052602160045260246000fd5b81528154602090910190610100900460ff1660028111156121aa57634e487b7160e01b600052602160045260246000fd5b60028111156121c957634e487b7160e01b600052602160045260246000fd5b8152905462010000810465ffffffffffff166020830152600160401b90046001600160801b031660409091015292915050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146122745760405162461bcd60e51b815260206004820152601f60248201527f4f6e6c7920565246436f6f7264696e61746f722063616e2066756c66696c6c006044820152606401610a87565b6114448282612c85565b6000828152602081905260409020600101546122998161266b565b6111d98383612ae0565b600080516020613f288339815191526122bb8161266b565b6000805b848110156124845760008781526008602052604081208787848181106122f557634e487b7160e01b600052603260045260246000fd5b9050602002013560016123089190613d4a565b8154811061232657634e487b7160e01b600052603260045260246000fd5b600091825260209091200180549091506001600160a01b03868116600160301b90920416146123975760405162461bcd60e51b815260206004820152601e60248201527f456e74727920646964206e6f742062656c6f6e6720746f20706c6179657200006044820152606401610a87565b80546601000000000000600160d01b031916815560008787848181106123cd57634e487b7160e01b600052603260045260246000fd5b90506020020135600014156123e45750600061244e565b600089815260086020526040902088888581811061241257634e487b7160e01b600052603260045260246000fd5b905060200201358154811061243757634e487b7160e01b600052603260045260246000fd5b60009182526020909120015465ffffffffffff1690505b815461246390829065ffffffffffff16613e0b565b61246d9085613d4a565b93505050808061247c90613e65565b9150506122bf565b50604080518281526001600160a01b038516602082015287917f2cca80c1af5abb202a642a502875436822768d733462843a7c3a902b0fad99d0910161170f565b600082815260086020526040812081906124df9084612d42565b6000858152600860205260408120805492935090918390811061251257634e487b7160e01b600052603260045260246000fd5b600091825260209091200154600160301b90046001600160a01b03169050801561253f5791506108ee9050565b6000825b811580156125985750600087815260086020526040812080548390811061257a57634e487b7160e01b600052603260045260246000fd5b600091825260209091200154600160301b90046001600160a01b0316145b156125cf57806125c4576000878152600860205260409020546125bd90600190613e0b565b9050612543565b6125bd600182613e0b565b81156126155760405162461bcd60e51b8152602060048201526015602482015274105b1b081d5cd95c9cc8189b1858dadb1a5cdd1959605a1b6044820152606401610a87565b600087815260086020526040902080548290811061264357634e487b7160e01b600052603260045260246000fd5b600091825260209091200154600160301b90046001600160a01b031694506108ee9350505050565b6105308133612e33565b6126a1604080516080810190915280600081526020016000815260006020820181905260409091015290565b6000600a83815481106126c457634e487b7160e01b600052603260045260246000fd5b6000918252602080832086845260079091526040909220910191506001825460ff16600681111561270557634e487b7160e01b600052602160045260246000fd5b1461274b5760405162461bcd60e51b8152602060048201526016602482015275526166666c6520696e2077726f6e672073746174757360501b6044820152606401610a87565b805482546001600160801b03918216600160401b90910490911610156127b35760405162461bcd60e51b815260206004820152601760248201527f4e6f7420656e6f7567682066756e6473207261697365640000000000000000006044820152606401610a87565b81548154600160401b9091046001600160801b03908116600160801b9092041611156128215760405162461bcd60e51b815260206004820152601860248201527f446573697265642066756e6473206e6f742072616973656400000000000000006044820152606401610a87565b815460ff19166004178083556040516001600160801b03600160401b90920491909116815284907ff2be214756d2fbc1e781d10809ddef33000009d805be55356bb348134ce21c689060200160405180910390a2604080516080810190915282548390829060ff1660068111156128a857634e487b7160e01b600052602160045260246000fd5b60068111156128c757634e487b7160e01b600052602160045260246000fd5b81528154602090910190610100900460ff1660028111156128f857634e487b7160e01b600052602160045260246000fd5b600281111561291757634e487b7160e01b600052602160045260246000fd5b8152905462010000810465ffffffffffff166020830152600160401b90046001600160801b0316604090910152949350505050565b6003546040516370a0823160e01b8152306004820152600091906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a082319060240160206040518083038186803b1580156129b257600080fd5b505afa1580156129c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129ea9190613865565b1015612a4c5760405162461bcd60e51b815260206004820152602b60248201527f4e6f7420656e6f756768204c494e4b202d2066696c6c20636f6e74726163742060448201526a1dda5d1a0819985d58d95d60aa1b6064820152608401610a87565b60006108ee600254600354612e97565b612a6682826120a7565b611444576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055612a9c3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b612aea82826120a7565b15611444576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b604080516080810190915260009080828152602001836002811115612b7a57634e487b7160e01b600052602160045260246000fd5b81526000602082018190526040909101819052600a8054600181810183559190925282517fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a890920180549394508493909291839160ff191690836006811115612bf357634e487b7160e01b600052602160045260246000fd5b021790555060208201518154829061ff001916610100836002811115612c2957634e487b7160e01b600052602160045260246000fd5b0217905550604082015181546060909301516001600160801b0316600160401b02600160401b600160c01b031965ffffffffffff90921662010000029190911662010000600160c01b0319909316929092179190911790555050565b6000828152600560209081526040808320815180830190925280548252600101549181018290529190612cb89084613ea6565b612cc3906001613d4a565b60408051808201825285815260208082018481528651600090815260048352849020835181559051600190910155855183518881529182018590529394509092917f7c40e661b8212d0c4f60ac6e6ebed99c28680c7b3ede5b82f3b0254543f62fca910160405180910390a28251612d3b9083613029565b5050505050565b8154600090612d53575060006108ee565b82546000905b80821015612dc6576000612d6d83836133e6565b905084868281548110612d9057634e487b7160e01b600052603260045260246000fd5b60009182526020909120015465ffffffffffff161115612db257809150612dc0565b612dbd816001613d4a565b92505b50612d59565b600082118015612e1257508385612dde600185613e0b565b81548110612dfc57634e487b7160e01b600052603260045260246000fd5b60009182526020909120015465ffffffffffff16145b15612e2b57612e22600183613e0b565b925050506108ee565b5090506108ee565b612e3d82826120a7565b61144457612e55816001600160a01b03166014613408565b612e60836020613408565b604051602001612e71929190613ac9565b60408051601f198184030181529082905262461bcd60e51b8252610a8791600401613c8d565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316634000aea07f000000000000000000000000000000000000000000000000000000000000000084866000604051602001612f07929190918252602082015260400190565b6040516020818303038152906040526040518463ffffffff1660e01b8152600401612f3493929190613b3e565b602060405180830381600087803b158015612f4e57600080fd5b505af1158015612f62573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f8691906136f8565b50600083815260016020818152604080842054815180840189905280830186905230606082015260808082018390528351808303909101815260a09091019092528151918301919091209387905290829052612fe191613d4a565b6000858152600160205260409020556130218482604080516020808201949094528082019290925280518083038201815260609092019052805191012090565b949350505050565b60006009838154811061304c57634e487b7160e01b600052603260045260246000fd5b906000526020600020906005020190506000600a848154811061307f57634e487b7160e01b600052603260045260246000fd5b600091825260209091200190506002815460ff1660068111156130b257634e487b7160e01b600052602160045260246000fd5b14806130e157506004815460ff1660068111156130df57634e487b7160e01b600052602160045260246000fd5b145b6131265760405162461bcd60e51b8152602060048201526016602482015275526166666c6520696e2077726f6e672073746174757360501b6044820152606401610a87565b6004820183905561313784846124c5565b6002830180546001600160a01b039283166001600160a01b0319909116178155825460ff1916600517835554600184015460405160009392909216918381818185875af1925050503d80600081146131ab576040519150601f19603f3d011682016040523d82523d6000602084013e6131b0565b606091505b50509050806131d15760405162461bcd60e51b8152600401610a8790613ca0565b82548254600091612710916131fe9165ffffffffffff1690600160401b90046001600160801b0316613dbd565b6132089190613d83565b83546001600160801b03918216925060009161322e918491600160401b90910416613e0b565b60038601546040519192506000916001600160a01b039091169083908381818185875af1925050503d8060008114613282576040519150601f19603f3d011682016040523d82523d6000602084013e613287565b606091505b50509050806132a85760405162461bcd60e51b8152600401610a8790613ca0565b600b546040516000916001600160a01b03169085908381818185875af1925050503d80600081146132f5576040519150601f19603f3d011682016040523d82523d6000602084013e6132fa565b606091505b50509050806133435760405162461bcd60e51b81526020600482015260156024820152744661696c65642073656e642045746820746f204d5760581b6044820152606401610a87565b887f7378e11c2b0ec7514bbf7ba369980eedcba0bca03e116dc9e7138f7748e211d68560405161337591815260200190565b60405180910390a26002870154865460408051600160401b9092046001600160801b03168252602082018b90526001600160a01b03909216918b917fe0b2a72a0644b093aac275024c05c7c28851a0b572557a32241d13634a0f3e08910160405180910390a3505050505050505050565b60006133f56002848418613da9565b61340190848416613d4a565b9392505050565b60606000613417836002613dec565b613422906002613d4a565b67ffffffffffffffff81111561344857634e487b7160e01b600052604160045260246000fd5b6040519080825280601f01601f191660200182016040528015613472576020820181803683370190505b509050600360fc1b8160008151811061349b57634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a905350600f60fb1b816001815181106134d857634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a90535060006134fc846002613dec565b613507906001613d4a565b90505b600181111561359b576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811061354957634e487b7160e01b600052603260045260246000fd5b1a60f81b82828151811061356d57634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a90535060049490941c9361359481613e4e565b905061350a565b5083156134015760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610a87565b80356135f581613f12565b919050565b8035600381106135f557600080fd5b80356001600160801b03811681146135f557600080fd5b803565ffffffffffff811681146135f557600080fd5b600060208284031215613647578081fd5b813561340181613f12565b60008060408385031215613664578081fd5b823561366f81613f12565b946020939093013593505050565b60008060008060808587031215613692578182fd5b843561369d81613f12565b93506020850135925060408501356136b481613f12565b9396929550929360600135925050565b6000806000606084860312156136d8578283fd5b83356136e381613f12565b95602085013595506040909401359392505050565b600060208284031215613709578081fd5b81518015158114613401578182fd5b600060208284031215613729578081fd5b5035919050565b60008060408385031215613742578182fd5b82359150602083013561375481613f12565b809150509250929050565b60008060408385031215613771578182fd5b50508035926020909101359150565b600060208284031215613791578081fd5b81356001600160e01b031981168114613401578182fd5b600080600080600080600060c0888a0312156137c2578283fd5b6137cb88613609565b9650602088013595506137e060408901613609565b9450606088013567ffffffffffffffff808211156137fc578485fd5b818a0191508a601f83011261380f578485fd5b81358181111561381d578586fd5b8b6020606083028501011115613831578586fd5b60208301965080955050505061384960808901613620565b915061385760a089016135fa565b905092959891949750929550565b600060208284031215613876578081fd5b5051919050565b6000806040838503121561388f578182fd5b8235915060208084013567ffffffffffffffff808211156138ae578384fd5b818601915086601f8301126138c1578384fd5b8135818111156138d3576138d3613efc565b8060051b604051601f19603f830116810181811085821117156138f8576138f8613efc565b604052828152858101935084860182860187018b1015613916578788fd5b8795505b8386101561393f5761392b816135ea565b85526001959095019493860193860161391a565b508096505050505050509250929050565b60008060008060608587031215613965578182fd5b84359350602085013567ffffffffffffffff80821115613983578384fd5b818701915087601f830112613996578384fd5b8135818111156139a4578485fd5b8860208260051b85010111156139b8578485fd5b60208301955080945050505060408501356139d281613f12565b939692955090935050565b6000806000606084860312156139f1578081fd5b83359250613a0160208501613620565b91506040840135613a1181613f12565b809150509250925092565b600060208284031215613a2d578081fd5b61340182613620565b6000815180845260208085019450808401835b83811015613a6e5781516001600160a01b031687529582019590820190600101613a49565b509495945050505050565b60008151808452613a91816020860160208601613e22565b601f01601f19169290920160200192915050565b60038110613ab557613ab5613ee6565b9052565b60078110613ab557613ab5613ee6565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351613b01816017850160208801613e22565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351613b32816028840160208801613e22565b01602801949350505050565b60018060a01b0384168152826020820152606060408201526000613b656060830184613a79565b95945050505050565b606081526000613b816060830186613a36565b905083602083015265ffffffffffff83166040830152949350505050565b606081526000613bb26060830186613a36565b65ffffffffffff94851660208401529290931660409091015292915050565b602080825282518282018190526000919060409081850190868401855b82811015613c24578151805165ffffffffffff1685528601516001600160a01b0316868501529284019290850190600101613bee565b5091979650505050505050565b82151581526040602082015260006130216040830184613a79565b60808101613c5a8287613ab9565b613c676020830186613aa5565b65ffffffffffff841660408301526001600160801b038316606083015295945050505050565b6020815260006134016020830184613a79565b6020808252601490820152732330b4b632b2103a379039b2b7321022ba3432b960611b604082015260600190565b6000608082019050613ce1828451613ab9565b6020830151613cf36020840182613aa5565b5065ffffffffffff60408401511660408301526001600160801b03606084015116606083015292915050565b60006001600160801b03808316818516808303821115613d4157613d41613eba565b01949350505050565b60008219821115613d5d57613d5d613eba565b500190565b600065ffffffffffff808316818516808303821115613d4157613d41613eba565b60006001600160801b0380841680613d9d57613d9d613ed0565b92169190910492915050565b600082613db857613db8613ed0565b500490565b60006001600160801b0380831681851681830481118215151615613de357613de3613eba565b02949350505050565b6000816000190483118215151615613e0657613e06613eba565b500290565b600082821015613e1d57613e1d613eba565b500390565b60005b83811015613e3d578181015183820152602001613e25565b83811115610cb85750506000910152565b600081613e5d57613e5d613eba565b506000190190565b6000600019821415613e7957613e79613eba565b5060010190565b600065ffffffffffff80831681811415613e9c57613e9c613eba565b6001019392505050565b600082613eb557613eb5613ed0565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461053057600080fdfe523a704056dcd17bcf83bed8b68c59416dac1119be77755efe3bde0a64e46e0ca264697066735822122036787320047eb33c762fc0bbdd5c7c3e7e9a3580100ff91636a7fff972c0077a64736f6c63430008040033000000000000000000000000f0d54349addcf704f77ae15b96510dea15cb7952000000000000000000000000514910771af9ca656af840dff83e8264ecf986caaa77729d3466ca35ae8d28b3bbac7cc36a5031efdc430821c02bc31a238af4450000000000000000000000000000000000000000000000000000000000000001

Deployed Bytecode

0x60806040526004361061021a5760003560e01c806353b7a59b1161012357806393a75d02116100ab578063d649214c1161006f578063d649214c14610789578063ddba6e6b146107a9578063eb99038c1461080f578063f369145514610833578063f5b541a61461085357600080fd5b806393a75d02146106c357806394985ddd146106f0578063a217fddf14610710578063babdf60b14610725578063d547741f1461076957600080fd5b80636ecc20da116100f25780636ecc20da146106085780637c903fc01461061b5780637fa4cacb1461064f57806381d12c581461066f57806391d14854146106a357600080fd5b806353b7a59b146105335780635d4bc0ce1461056b5780635fba3171146105c85780636371ba0d146105e857600080fd5b8063248a9ca3116101a657806336568abe1161017557806336568abe14610478578063365e36581461049857806336734e34146104c55780633a3956c2146104e55780634239a50c1461051557600080fd5b8063248a9ca3146103b15780632a596800146103ef5780632f2ff15d14610438578063317f30591461045857600080fd5b80630b148ff0116101ed5780630b148ff01461031b5780630df716021461033d5780631e6cd3951461035d5780631fe968571461037d578063236854961461039e57600080fd5b8063013805c51461021f57806301ffc9a71461026a578063039be5581461029a578063043a1c9a146102fb575b600080fd5b34801561022b57600080fd5b5061023f61023a36600461375f565b610875565b6040805165ffffffffffff90931683526001600160a01b039091166020830152015b60405180910390f35b34801561027657600080fd5b5061028a610285366004613780565b6108bd565b6040519015158152602001610261565b3480156102a657600080fd5b506102db6102b5366004613718565b6007602052600090815260409020546001600160801b0380821691600160801b90041682565b604080516001600160801b03938416815292909116602083015201610261565b34801561030757600080fd5b5061028a610316366004613652565b6108f4565b34801561032757600080fd5b5061033b6103363660046139dd565b61098d565b005b34801561034957600080fd5b5061033b610358366004613718565b610c49565b34801561036957600080fd5b5061028a610378366004613718565b610cbe565b34801561038957600080fd5b5061028a610398366004613636565b50600090565b61033b6103ac36600461375f565b610de9565b3480156103bd57600080fd5b506103e16103cc366004613718565b60009081526020819052604090206001015490565b604051908152602001610261565b3480156103fb57600080fd5b5061042361040a366004613718565b6005602052600090815260409020805460019091015482565b60408051928352602083019190915201610261565b34801561044457600080fd5b5061033b610453366004613730565b6111b4565b34801561046457600080fd5b5061033b610473366004613718565b6111de565b34801561048457600080fd5b5061033b610493366004613730565b6113ca565b3480156104a457600080fd5b506104b86104b3366004613718565b611448565b6040516102619190613bd1565b3480156104d157600080fd5b5061033b6104e036600461387d565b6114d6565b3480156104f157600080fd5b50610505610500366004613718565b61171f565b6040516102619493929190613c4c565b34801561052157600080fd5b5061033b610530366004613718565b50565b34801561053f57600080fd5b50600b54610553906001600160a01b031681565b6040516001600160a01b039091168152602001610261565b34801561057757600080fd5b5061058b610586366004613718565b61176b565b6040805165ffffffffffff909616865260208601949094526001600160a01b0392831693850193909352166060830152608082015260a001610261565b3480156105d457600080fd5b5061033b6105e3366004613718565b6117c2565b3480156105f457600080fd5b506103e16106033660046137a8565b611a61565b61033b610616366004613718565b611f17565b34801561062757600080fd5b506103e17fde5ee446972f4e39ab62c03aa34b2096680a875c3fdb3eb2f947cbb93341c05881565b34801561065b57600080fd5b5061033b61066a366004613636565b612079565b34801561067b57600080fd5b5061042361068a366004613718565b6004602052600090815260409020805460019091015482565b3480156106af57600080fd5b5061028a6106be366004613730565b6120a7565b3480156106cf57600080fd5b506106e36106de366004613718565b6120d0565b6040516102619190613cce565b3480156106fc57600080fd5b5061033b61070b36600461375f565b6121fc565b34801561071c57600080fd5b506103e1600081565b34801561073157600080fd5b5061075b61074036600461367d565b60408051602081019091526000815260019094509492505050565b604051610261929190613c31565b34801561077557600080fd5b5061033b610784366004613730565b61227e565b34801561079557600080fd5b5061033b6107a4366004613950565b6122a3565b3480156107b557600080fd5b506107ed6107c4366004613718565b600660205260009081526040902080546001820154600290920154909165ffffffffffff169083565b6040805193845265ffffffffffff909216602084015290820152606001610261565b34801561081b57600080fd5b5061028a61082a3660046136c4565b60009392505050565b34801561083f57600080fd5b5061055361084e36600461375f565b6124c5565b34801561085f57600080fd5b506103e1600080516020613f2883398151915281565b6008602052816000526040600020818154811061089157600080fd5b60009182526020909120015465ffffffffffff81169250600160301b90046001600160a01b0316905082565b60006001600160e01b03198216637965db0b60e01b14806108ee57506301ffc9a760e01b6001600160e01b03198316145b92915050565b6000806009838154811061091857634e487b7160e01b600052603260045260246000fd5b60009182526020918290206040805160a0810182526005909302909101805465ffffffffffff16835260018101549383019390935260028301546001600160a01b0390811691830191909152600383015481166060830181905260049093015460809092019190915285161491505092915050565b7fde5ee446972f4e39ab62c03aa34b2096680a875c3fdb3eb2f947cbb93341c0586109b78161266b565b6000600a85815481106109da57634e487b7160e01b600052603260045260246000fd5b6000918252602090912001905060018154610100900460ff166002811115610a1257634e487b7160e01b600052602160045260246000fd5b1480610a46575060028154610100900460ff166002811115610a4457634e487b7160e01b600052602160045260246000fd5b145b610a905760405162461bcd60e51b8152602060048201526016602482015275115b9d1c9e481d1e5c19481b9bdd08185b1b1bddd95960521b60448201526064015b60405180910390fd5b60006040518060400160405280868460000160029054906101000a900465ffffffffffff16610abf9190613d62565b65ffffffffffff90811682526001600160a01b0380881660209384015260008a8152600884526040812080546001810182559082529084902085519101805494860151909216600160301b026001600160d01b03199094169083161792909217909155835491925086918491600291610b4091859162010000900416613d62565b92506101000a81548165ffffffffffff021916908365ffffffffffff1602179055506000600167ffffffffffffffff811115610b8c57634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015610bb5578160200160208202803683370190505b5090508481600081518110610bda57634e487b7160e01b600052603260045260246000fd5b6001600160a01b0390921660209283029190910190910152825460405188917f4da4f5fab0816c65315b6f5d15f879f96b98661133d7b3787788f291367604fb91610c389185918b9165ffffffffffff620100009091041690613b9f565b60405180910390a250505050505050565b600080516020613f28833981519152610c618161266b565b6000610c6c83612675565b90506000610c7861294c565b9050610cb884836040015165ffffffffffff1683604080518082018252938452602080850193845260009283526005905290209151825551600190910155565b50505050565b600080600a8381548110610ce257634e487b7160e01b600052603260045260246000fd5b60009182526020909120604080516080810190915291018054829060ff166006811115610d1f57634e487b7160e01b600052602160045260246000fd5b6006811115610d3e57634e487b7160e01b600052602160045260246000fd5b81528154602090910190610100900460ff166002811115610d6f57634e487b7160e01b600052602160045260246000fd5b6002811115610d8e57634e487b7160e01b600052602160045260246000fd5b8152905462010000810465ffffffffffff166020830152600160401b90046001600160801b03166040909101529050600181516006811115610de057634e487b7160e01b600052602160045260246000fd5b14159392505050565b6000600a8381548110610e0c57634e487b7160e01b600052603260045260246000fd5b600091825260209091200190506001815460ff166006811115610e3f57634e487b7160e01b600052602160045260246000fd5b14610e7f5760405163efeb42cf60e01b815260206004820152600f60248201526e139bdd081a5b881050d0d154151151608a1b6044820152606401610a87565b60018154610100900460ff166002811115610eaa57634e487b7160e01b600052602160045260246000fd5b1415610ef25760405163efeb42cf60e01b8152602060048201526016602482015275115b9d1c9e481d1e5c19481b9bdd08185b1b1bddd95960521b6044820152606401610a87565b81610f2f5760405163efeb42cf60e01b815260206004820152600c60248201526b0686f774d616e7920697320360a41b6044820152606401610a87565b60008281526006602090815260409182902082516060810184528154808252600183015465ffffffffffff1693820193909352600290910154928101929092528414610fb35760405163efeb42cf60e01b81526020600482015260126024820152711259081b9bdd081a5b881c9859999b19525960721b6044820152606401610a87565b602081015165ffffffffffff81166110015760405163efeb42cf60e01b815260206004820152601060248201526f1259081b9bdd081cdd5c1c1bdc9d195960821b6044820152606401610a87565b816040015134146110615760405163efeb42cf60e01b8152602060048201526024808201527f6d73672e76616c7565206d75737420626520657175616c20746f2074686520706044820152637269636560e01b6064820152608401610a87565b8254604080518082019091526201000090910465ffffffffffff16906000908061108b8585613d62565b65ffffffffffff90811682523360209283015260008a8152600880845260408220805460018101825590835291849020855192018054948601516001600160a01b0316600160301b026001600160d01b03199095169290931691909117929092179055865491925034918791906111149084906001600160801b03600160401b90910416613d1f565b92506101000a8154816001600160801b0302191690836001600160801b0316021790555082826111449190613d62565b855467ffffffffffff000019166201000065ffffffffffff9283168102919091178088556040805192909104909216815260208101889052339189917fd746af8dc82f9bed98cea0fe0264eb1c3d2e5f7bcc77fc5efb429c79df407887910160405180910390a350505050505050565b6000828152602081905260409020600101546111cf8161266b565b6111d98383612a5c565b505050565b600080516020613f288339815191526111f68161266b565b6000600a838154811061121957634e487b7160e01b600052603260045260246000fd5b600091825260209091200190506006815460ff16600681111561124c57634e487b7160e01b600052602160045260246000fd5b148061127b57506003815460ff16600681111561127957634e487b7160e01b600052602160045260246000fd5b145b6112b65760405162461bcd60e51b815260206004820152600c60248201526b57726f6e672073746174757360a01b6044820152606401610a87565b805460ff1916600317808255600b546040516000926001600160a01b03909216916001600160801b03600160401b90910416908381818185875af1925050503d8060008114611321576040519150601f19603f3d011682016040523d82523d6000602084013e611326565b606091505b505090508061136d5760405162461bcd60e51b81526020600482015260136024820152724661696c2073656e642045746820746f204d5760681b6044820152606401610a87565b8154604051600160401b9091046001600160801b0316815284907fcdef6558dae40f2699846eedf449462daab85b1224ad7f077569ba91aaa949259060200160405180910390a2508054600160401b600160c01b03191690555050565b6001600160a01b038116331461143a5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401610a87565b6114448282612ae0565b5050565b606060086000838152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b828210156114cb576000848152602090819020604080518082019091529084015465ffffffffffff81168252600160301b90046001600160a01b03168183015282526001909201910161147d565b505050509050919050565b600080516020613f288339815191526114ee8161266b565b6000600a848154811061151157634e487b7160e01b600052603260045260246000fd5b600091825260209091200190506001815460ff16600681111561154457634e487b7160e01b600052602160045260246000fd5b146115915760405162461bcd60e51b815260206004820152601960248201527f526166666c65206973206e6f7420696e206163636570746564000000000000006044820152606401610a87565b82516000805b828110156116935760008682815181106115c157634e487b7160e01b600052603260045260246000fd5b6020026020010151905060006040518060400160405280848860000160029054906101000a900465ffffffffffff1665ffffffffffff166116029190613d4a565b61160d906001613d4a565b65ffffffffffff90811682526001600160a01b0380861660209384015260008d8152600884526040812080546001810182559082529084902085519101805494860151909216600160301b026001600160d01b0319909416921691909117919091179055905061167c84613e80565b93505050808061168b90613e65565b915050611597565b5082546116af90829062010000900465ffffffffffff16613d62565b835467ffffffffffff000019166201000065ffffffffffff92831681029190911780865560405189937f4da4f5fab0816c65315b6f5d15f879f96b98661133d7b3787788f291367604fb9361170f938b9389939290910490911690613b6e565b60405180910390a2505050505050565b600a818154811061172f57600080fd5b60009182526020909120015460ff80821692506101008204169062010000810465ffffffffffff1690600160401b90046001600160801b031684565b6009818154811061177b57600080fd5b60009182526020909120600590910201805460018201546002830154600384015460049094015465ffffffffffff909316945090926001600160a01b039182169291169085565b600080516020613f288339815191526117da8161266b565b6000600983815481106117fd57634e487b7160e01b600052603260045260246000fd5b906000526020600020906005020190506000600a848154811061183057634e487b7160e01b600052603260045260246000fd5b600091825260209091200190506005815460ff16600681111561186357634e487b7160e01b600052602160045260246000fd5b1415801561189557506003815460ff16600681111561189257634e487b7160e01b600052602160045260246000fd5b14155b80156118c557506002815460ff1660068111156118c257634e487b7160e01b600052602160045260246000fd5b14155b80156118f557506004815460ff1660068111156118f257634e487b7160e01b600052602160045260246000fd5b14155b801561192557506006815460ff16600681111561192257634e487b7160e01b600052602160045260246000fd5b14155b6119605760405162461bcd60e51b815260206004820152600c60248201526b57726f6e672073746174757360a01b6044820152606401610a87565b6001815460ff16600681111561198657634e487b7160e01b600052602160045260246000fd5b1415611a0757600382015460018301546040516000926001600160a01b031691908381818185875af1925050503d80600081146119df576040519150601f19603f3d011682016040523d82523d6000602084013e6119e4565b606091505b5050905080611a055760405162461bcd60e51b8152600401610a8790613ca0565b505b805460ff19166006178082556040516001600160801b03600160401b90920491909116815284907fd512a34b0f0618078770fcd85d974df1ab46a7882e8b3d45aa91764f4961aed29060200160405180910390a250505050565b6000600080516020613f28833981519152611a7b8161266b565b6113888465ffffffffffff161115611acb5760405162461bcd60e51b81526020600482015260136024820152720c6dedadad2e6e6d2dedc40e8dede40d0d2ced606b1b6044820152606401610a87565b6040805160a08101825265ffffffffffff8681168252602082018b81526000938301848152606084018581526080850186815260098054600181018255975285517f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af6005909802978801805465ffffffffffff1916919096161790945591517f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7b0860155517f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7b1850180546001600160a01b03199081166001600160a01b039384161790915591517f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7b2860180549093169116179055517f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7b390920191909155611c1084612b45565b600954600090611c2290600190613e0b565b905086611c5d5760405162461bcd60e51b81526020600482015260096024820152684e6f2070726963657360b81b6044820152606401610a87565b60005b87811015611df6576000898983818110611c8a57634e487b7160e01b600052603260045260246000fd5b9050606002016020016020810190611ca29190613a1c565b65ffffffffffff1611611ce95760405162461bcd60e51b815260206004820152600f60248201526e06e756d456e7472696573206973203608c1b6044820152606401610a87565b600060405180606001604052808481526020018b8b85818110611d1c57634e487b7160e01b600052603260045260246000fd5b9050606002016020016020810190611d349190613a1c565b65ffffffffffff1681526020018b8b85818110611d6157634e487b7160e01b600052603260045260246000fd5b90506060020160400135815250905080600660008c8c86818110611d9557634e487b7160e01b600052603260045260246000fd5b60600291909101358252506020808201929092526040908101600020835181559183015160018301805465ffffffffffff191665ffffffffffff90921691909117905591909101516002909101555080611dee81613e65565b915050611c60565b506040805180820182526001600160801b03808c1682528d8116602080840191825260008681526007909152848120935191518316600160801b02919092161790915590518b9183917ff6f5afeb49bc62176d1efaa06a1753999cc29bf378f1004ea916f37f41d7638a9190a360408051808201825260018082523360208084019182526000868152600882529485208054938401815580865290852084519301805492516001600160a01b0316600160301b026001600160d01b031990931665ffffffffffff949094169390931791909117909155838352805491929091611eef57634e487b7160e01b600052603260045260246000fd5b600091825260209091200180546001600160d01b0319169055509a9950505050505050505050565b6000600a8281548110611f3a57634e487b7160e01b600052603260045260246000fd5b906000526020600020019050600060098381548110611f6957634e487b7160e01b600052603260045260246000fd5b6000918252602082206005909102019150825460ff166006811115611f9e57634e487b7160e01b600052602160045260246000fd5b14611fe05760405162461bcd60e51b8152602060048201526012602482015271149859999b19481b9bdd0810d4915055115160721b6044820152606401610a87565b348160010154146120265760405162461bcd60e51b815260206004820152601060248201526f141c9a5e99481b9bdd081cdd185ad95960821b6044820152606401610a87565b815460ff19166001178255600381018054336001600160a01b0319909116811790915560405184907f8bb509eedfd1c4847b0a8a2b4493cf2ebb9970dc367e477cd2a8523e212dc1db90600090a3505050565b60006120848161266b565b50600b80546001600160a01b0319166001600160a01b0392909216919091179055565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b6120fc604080516080810190915280600081526020016000815260006020820181905260409091015290565b600a828154811061211d57634e487b7160e01b600052603260045260246000fd5b60009182526020909120604080516080810190915291018054829060ff16600681111561215a57634e487b7160e01b600052602160045260246000fd5b600681111561217957634e487b7160e01b600052602160045260246000fd5b81528154602090910190610100900460ff1660028111156121aa57634e487b7160e01b600052602160045260246000fd5b60028111156121c957634e487b7160e01b600052602160045260246000fd5b8152905462010000810465ffffffffffff166020830152600160401b90046001600160801b031660409091015292915050565b336001600160a01b037f000000000000000000000000f0d54349addcf704f77ae15b96510dea15cb795216146122745760405162461bcd60e51b815260206004820152601f60248201527f4f6e6c7920565246436f6f7264696e61746f722063616e2066756c66696c6c006044820152606401610a87565b6114448282612c85565b6000828152602081905260409020600101546122998161266b565b6111d98383612ae0565b600080516020613f288339815191526122bb8161266b565b6000805b848110156124845760008781526008602052604081208787848181106122f557634e487b7160e01b600052603260045260246000fd5b9050602002013560016123089190613d4a565b8154811061232657634e487b7160e01b600052603260045260246000fd5b600091825260209091200180549091506001600160a01b03868116600160301b90920416146123975760405162461bcd60e51b815260206004820152601e60248201527f456e74727920646964206e6f742062656c6f6e6720746f20706c6179657200006044820152606401610a87565b80546601000000000000600160d01b031916815560008787848181106123cd57634e487b7160e01b600052603260045260246000fd5b90506020020135600014156123e45750600061244e565b600089815260086020526040902088888581811061241257634e487b7160e01b600052603260045260246000fd5b905060200201358154811061243757634e487b7160e01b600052603260045260246000fd5b60009182526020909120015465ffffffffffff1690505b815461246390829065ffffffffffff16613e0b565b61246d9085613d4a565b93505050808061247c90613e65565b9150506122bf565b50604080518281526001600160a01b038516602082015287917f2cca80c1af5abb202a642a502875436822768d733462843a7c3a902b0fad99d0910161170f565b600082815260086020526040812081906124df9084612d42565b6000858152600860205260408120805492935090918390811061251257634e487b7160e01b600052603260045260246000fd5b600091825260209091200154600160301b90046001600160a01b03169050801561253f5791506108ee9050565b6000825b811580156125985750600087815260086020526040812080548390811061257a57634e487b7160e01b600052603260045260246000fd5b600091825260209091200154600160301b90046001600160a01b0316145b156125cf57806125c4576000878152600860205260409020546125bd90600190613e0b565b9050612543565b6125bd600182613e0b565b81156126155760405162461bcd60e51b8152602060048201526015602482015274105b1b081d5cd95c9cc8189b1858dadb1a5cdd1959605a1b6044820152606401610a87565b600087815260086020526040902080548290811061264357634e487b7160e01b600052603260045260246000fd5b600091825260209091200154600160301b90046001600160a01b031694506108ee9350505050565b6105308133612e33565b6126a1604080516080810190915280600081526020016000815260006020820181905260409091015290565b6000600a83815481106126c457634e487b7160e01b600052603260045260246000fd5b6000918252602080832086845260079091526040909220910191506001825460ff16600681111561270557634e487b7160e01b600052602160045260246000fd5b1461274b5760405162461bcd60e51b8152602060048201526016602482015275526166666c6520696e2077726f6e672073746174757360501b6044820152606401610a87565b805482546001600160801b03918216600160401b90910490911610156127b35760405162461bcd60e51b815260206004820152601760248201527f4e6f7420656e6f7567682066756e6473207261697365640000000000000000006044820152606401610a87565b81548154600160401b9091046001600160801b03908116600160801b9092041611156128215760405162461bcd60e51b815260206004820152601860248201527f446573697265642066756e6473206e6f742072616973656400000000000000006044820152606401610a87565b815460ff19166004178083556040516001600160801b03600160401b90920491909116815284907ff2be214756d2fbc1e781d10809ddef33000009d805be55356bb348134ce21c689060200160405180910390a2604080516080810190915282548390829060ff1660068111156128a857634e487b7160e01b600052602160045260246000fd5b60068111156128c757634e487b7160e01b600052602160045260246000fd5b81528154602090910190610100900460ff1660028111156128f857634e487b7160e01b600052602160045260246000fd5b600281111561291757634e487b7160e01b600052602160045260246000fd5b8152905462010000810465ffffffffffff166020830152600160401b90046001600160801b0316604090910152949350505050565b6003546040516370a0823160e01b8152306004820152600091906001600160a01b037f000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca16906370a082319060240160206040518083038186803b1580156129b257600080fd5b505afa1580156129c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129ea9190613865565b1015612a4c5760405162461bcd60e51b815260206004820152602b60248201527f4e6f7420656e6f756768204c494e4b202d2066696c6c20636f6e74726163742060448201526a1dda5d1a0819985d58d95d60aa1b6064820152608401610a87565b60006108ee600254600354612e97565b612a6682826120a7565b611444576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055612a9c3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b612aea82826120a7565b15611444576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b604080516080810190915260009080828152602001836002811115612b7a57634e487b7160e01b600052602160045260246000fd5b81526000602082018190526040909101819052600a8054600181810183559190925282517fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a890920180549394508493909291839160ff191690836006811115612bf357634e487b7160e01b600052602160045260246000fd5b021790555060208201518154829061ff001916610100836002811115612c2957634e487b7160e01b600052602160045260246000fd5b0217905550604082015181546060909301516001600160801b0316600160401b02600160401b600160c01b031965ffffffffffff90921662010000029190911662010000600160c01b0319909316929092179190911790555050565b6000828152600560209081526040808320815180830190925280548252600101549181018290529190612cb89084613ea6565b612cc3906001613d4a565b60408051808201825285815260208082018481528651600090815260048352849020835181559051600190910155855183518881529182018590529394509092917f7c40e661b8212d0c4f60ac6e6ebed99c28680c7b3ede5b82f3b0254543f62fca910160405180910390a28251612d3b9083613029565b5050505050565b8154600090612d53575060006108ee565b82546000905b80821015612dc6576000612d6d83836133e6565b905084868281548110612d9057634e487b7160e01b600052603260045260246000fd5b60009182526020909120015465ffffffffffff161115612db257809150612dc0565b612dbd816001613d4a565b92505b50612d59565b600082118015612e1257508385612dde600185613e0b565b81548110612dfc57634e487b7160e01b600052603260045260246000fd5b60009182526020909120015465ffffffffffff16145b15612e2b57612e22600183613e0b565b925050506108ee565b5090506108ee565b612e3d82826120a7565b61144457612e55816001600160a01b03166014613408565b612e60836020613408565b604051602001612e71929190613ac9565b60408051601f198184030181529082905262461bcd60e51b8252610a8791600401613c8d565b60007f000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca6001600160a01b0316634000aea07f000000000000000000000000f0d54349addcf704f77ae15b96510dea15cb795284866000604051602001612f07929190918252602082015260400190565b6040516020818303038152906040526040518463ffffffff1660e01b8152600401612f3493929190613b3e565b602060405180830381600087803b158015612f4e57600080fd5b505af1158015612f62573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f8691906136f8565b50600083815260016020818152604080842054815180840189905280830186905230606082015260808082018390528351808303909101815260a09091019092528151918301919091209387905290829052612fe191613d4a565b6000858152600160205260409020556130218482604080516020808201949094528082019290925280518083038201815260609092019052805191012090565b949350505050565b60006009838154811061304c57634e487b7160e01b600052603260045260246000fd5b906000526020600020906005020190506000600a848154811061307f57634e487b7160e01b600052603260045260246000fd5b600091825260209091200190506002815460ff1660068111156130b257634e487b7160e01b600052602160045260246000fd5b14806130e157506004815460ff1660068111156130df57634e487b7160e01b600052602160045260246000fd5b145b6131265760405162461bcd60e51b8152602060048201526016602482015275526166666c6520696e2077726f6e672073746174757360501b6044820152606401610a87565b6004820183905561313784846124c5565b6002830180546001600160a01b039283166001600160a01b0319909116178155825460ff1916600517835554600184015460405160009392909216918381818185875af1925050503d80600081146131ab576040519150601f19603f3d011682016040523d82523d6000602084013e6131b0565b606091505b50509050806131d15760405162461bcd60e51b8152600401610a8790613ca0565b82548254600091612710916131fe9165ffffffffffff1690600160401b90046001600160801b0316613dbd565b6132089190613d83565b83546001600160801b03918216925060009161322e918491600160401b90910416613e0b565b60038601546040519192506000916001600160a01b039091169083908381818185875af1925050503d8060008114613282576040519150601f19603f3d011682016040523d82523d6000602084013e613287565b606091505b50509050806132a85760405162461bcd60e51b8152600401610a8790613ca0565b600b546040516000916001600160a01b03169085908381818185875af1925050503d80600081146132f5576040519150601f19603f3d011682016040523d82523d6000602084013e6132fa565b606091505b50509050806133435760405162461bcd60e51b81526020600482015260156024820152744661696c65642073656e642045746820746f204d5760581b6044820152606401610a87565b887f7378e11c2b0ec7514bbf7ba369980eedcba0bca03e116dc9e7138f7748e211d68560405161337591815260200190565b60405180910390a26002870154865460408051600160401b9092046001600160801b03168252602082018b90526001600160a01b03909216918b917fe0b2a72a0644b093aac275024c05c7c28851a0b572557a32241d13634a0f3e08910160405180910390a3505050505050505050565b60006133f56002848418613da9565b61340190848416613d4a565b9392505050565b60606000613417836002613dec565b613422906002613d4a565b67ffffffffffffffff81111561344857634e487b7160e01b600052604160045260246000fd5b6040519080825280601f01601f191660200182016040528015613472576020820181803683370190505b509050600360fc1b8160008151811061349b57634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a905350600f60fb1b816001815181106134d857634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a90535060006134fc846002613dec565b613507906001613d4a565b90505b600181111561359b576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811061354957634e487b7160e01b600052603260045260246000fd5b1a60f81b82828151811061356d57634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a90535060049490941c9361359481613e4e565b905061350a565b5083156134015760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610a87565b80356135f581613f12565b919050565b8035600381106135f557600080fd5b80356001600160801b03811681146135f557600080fd5b803565ffffffffffff811681146135f557600080fd5b600060208284031215613647578081fd5b813561340181613f12565b60008060408385031215613664578081fd5b823561366f81613f12565b946020939093013593505050565b60008060008060808587031215613692578182fd5b843561369d81613f12565b93506020850135925060408501356136b481613f12565b9396929550929360600135925050565b6000806000606084860312156136d8578283fd5b83356136e381613f12565b95602085013595506040909401359392505050565b600060208284031215613709578081fd5b81518015158114613401578182fd5b600060208284031215613729578081fd5b5035919050565b60008060408385031215613742578182fd5b82359150602083013561375481613f12565b809150509250929050565b60008060408385031215613771578182fd5b50508035926020909101359150565b600060208284031215613791578081fd5b81356001600160e01b031981168114613401578182fd5b600080600080600080600060c0888a0312156137c2578283fd5b6137cb88613609565b9650602088013595506137e060408901613609565b9450606088013567ffffffffffffffff808211156137fc578485fd5b818a0191508a601f83011261380f578485fd5b81358181111561381d578586fd5b8b6020606083028501011115613831578586fd5b60208301965080955050505061384960808901613620565b915061385760a089016135fa565b905092959891949750929550565b600060208284031215613876578081fd5b5051919050565b6000806040838503121561388f578182fd5b8235915060208084013567ffffffffffffffff808211156138ae578384fd5b818601915086601f8301126138c1578384fd5b8135818111156138d3576138d3613efc565b8060051b604051601f19603f830116810181811085821117156138f8576138f8613efc565b604052828152858101935084860182860187018b1015613916578788fd5b8795505b8386101561393f5761392b816135ea565b85526001959095019493860193860161391a565b508096505050505050509250929050565b60008060008060608587031215613965578182fd5b84359350602085013567ffffffffffffffff80821115613983578384fd5b818701915087601f830112613996578384fd5b8135818111156139a4578485fd5b8860208260051b85010111156139b8578485fd5b60208301955080945050505060408501356139d281613f12565b939692955090935050565b6000806000606084860312156139f1578081fd5b83359250613a0160208501613620565b91506040840135613a1181613f12565b809150509250925092565b600060208284031215613a2d578081fd5b61340182613620565b6000815180845260208085019450808401835b83811015613a6e5781516001600160a01b031687529582019590820190600101613a49565b509495945050505050565b60008151808452613a91816020860160208601613e22565b601f01601f19169290920160200192915050565b60038110613ab557613ab5613ee6565b9052565b60078110613ab557613ab5613ee6565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351613b01816017850160208801613e22565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351613b32816028840160208801613e22565b01602801949350505050565b60018060a01b0384168152826020820152606060408201526000613b656060830184613a79565b95945050505050565b606081526000613b816060830186613a36565b905083602083015265ffffffffffff83166040830152949350505050565b606081526000613bb26060830186613a36565b65ffffffffffff94851660208401529290931660409091015292915050565b602080825282518282018190526000919060409081850190868401855b82811015613c24578151805165ffffffffffff1685528601516001600160a01b0316868501529284019290850190600101613bee565b5091979650505050505050565b82151581526040602082015260006130216040830184613a79565b60808101613c5a8287613ab9565b613c676020830186613aa5565b65ffffffffffff841660408301526001600160801b038316606083015295945050505050565b6020815260006134016020830184613a79565b6020808252601490820152732330b4b632b2103a379039b2b7321022ba3432b960611b604082015260600190565b6000608082019050613ce1828451613ab9565b6020830151613cf36020840182613aa5565b5065ffffffffffff60408401511660408301526001600160801b03606084015116606083015292915050565b60006001600160801b03808316818516808303821115613d4157613d41613eba565b01949350505050565b60008219821115613d5d57613d5d613eba565b500190565b600065ffffffffffff808316818516808303821115613d4157613d41613eba565b60006001600160801b0380841680613d9d57613d9d613ed0565b92169190910492915050565b600082613db857613db8613ed0565b500490565b60006001600160801b0380831681851681830481118215151615613de357613de3613eba565b02949350505050565b6000816000190483118215151615613e0657613e06613eba565b500290565b600082821015613e1d57613e1d613eba565b500390565b60005b83811015613e3d578181015183820152602001613e25565b83811115610cb85750506000910152565b600081613e5d57613e5d613eba565b506000190190565b6000600019821415613e7957613e79613eba565b5060010190565b600065ffffffffffff80831681811415613e9c57613e9c613eba565b6001019392505050565b600082613eb557613eb5613ed0565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461053057600080fdfe523a704056dcd17bcf83bed8b68c59416dac1119be77755efe3bde0a64e46e0ca264697066735822122036787320047eb33c762fc0bbdd5c7c3e7e9a3580100ff91636a7fff972c0077a64736f6c63430008040033

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

000000000000000000000000f0d54349addcf704f77ae15b96510dea15cb7952000000000000000000000000514910771af9ca656af840dff83e8264ecf986caaa77729d3466ca35ae8d28b3bbac7cc36a5031efdc430821c02bc31a238af4450000000000000000000000000000000000000000000000000000000000000001

-----Decoded View---------------
Arg [0] : _vrfCoordinator (address): 0xf0d54349aDdcf704F77AE15b96510dEA15cb7952
Arg [1] : _linkToken (address): 0x514910771AF9Ca656af840dff83E8264EcF986CA
Arg [2] : _keyHash (bytes32): 0xaa77729d3466ca35ae8d28b3bbac7cc36a5031efdc430821c02bc31a238af445
Arg [3] : _mainetFee (bool): True

-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000f0d54349addcf704f77ae15b96510dea15cb7952
Arg [1] : 000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca
Arg [2] : aa77729d3466ca35ae8d28b3bbac7cc36a5031efdc430821c02bc31a238af445
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000001


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.