Contract 0xe25f76bf0dbeba61683320a48f1aac887360a8df 1

Contract Overview

Balance:
0 MATIC

Token:
Txn Hash Method
Block
From
To
Value [Txn Fee]
0x527e3b2d71273a2baa267db4687ac04776dd854b3d20276fa7c0fe99c7daa04aClose Lottery270435202022-07-05 19:21:553 mins ago0x6456be06d125c0b7f661e6e09e695af4d59d58d1 IN  0xe25f76bf0dbeba61683320a48f1aac887360a8df0 MATIC0.00191263204412.9461076
0x0477a0c687126a514b3141ff0c5e1723404960f2207f81636df8d896087aca45Start Lottery270407672022-07-05 15:10:264 hrs 14 mins ago0x6456be06d125c0b7f661e6e09e695af4d59d58d1 IN  0xe25f76bf0dbeba61683320a48f1aac887360a8df0 MATIC0.0001787586
0x5ad1f53f32f2aec8064acf72746b31ee920fbe4616c88e409a7900545a04c74dDraw Final Numbe...270407432022-07-05 15:08:264 hrs 16 mins ago0x6456be06d125c0b7f661e6e09e695af4d59d58d1 IN  0xe25f76bf0dbeba61683320a48f1aac887360a8df0 MATIC0.000187866
0x973e5969a442151e556a385fa2037708b3f6d3b58b2b309698dcfa51c9460290Start Lottery270390462022-07-05 12:19:557 hrs 5 mins ago0x6456be06d125c0b7f661e6e09e695af4d59d58d1 IN  0xe25f76bf0dbeba61683320a48f1aac887360a8df0 MATIC0.0001192199993.999999994
0x3c3b843ce8499eef5fb7f94802fea9f917e7b195ca7b36ad37c199acbd8f26f9Draw Final Numbe...270383822022-07-05 11:08:248 hrs 16 mins ago0x6456be06d125c0b7f661e6e09e695af4d59d58d1 IN  0xe25f76bf0dbeba61683320a48f1aac887360a8df0 MATIC0.000156555.000000016
0x4b920f05d234a69f1a1d9a17c730280d2c6b2919c03e1bcdb49e4a4fd40bfa79Start Lottery270355832022-07-05 6:10:2413 hrs 14 mins ago0x6456be06d125c0b7f661e6e09e695af4d59d58d1 IN  0xe25f76bf0dbeba61683320a48f1aac887360a8df0 MATIC0.0001490255.000000032
0x7c634e71fbff1d4e4fe673f11c287ff8082cb99fc7b56272059bec932046865aDraw Final Numbe...270355592022-07-05 6:08:2413 hrs 16 mins ago0x6456be06d125c0b7f661e6e09e695af4d59d58d1 IN  0xe25f76bf0dbeba61683320a48f1aac887360a8df0 MATIC0.0001518535014.850000056
0xc60d4cf372af9c27c5b782180c548ed8206c1ea23b4c3691c9ca46a0ab213aa1Start Lottery270348882022-07-05 4:10:5215 hrs 14 mins ago0x6456be06d125c0b7f661e6e09e695af4d59d58d1 IN  0xe25f76bf0dbeba61683320a48f1aac887360a8df0 MATIC0.0012181113033.000000748
0x1c8c72186fa774499bc8c6b706accadbba760e875a0a832d1570ca673c47969bDraw Final Numbe...270348882022-07-05 4:10:5215 hrs 14 mins ago0x6456be06d125c0b7f661e6e09e695af4d59d58d1 IN  0xe25f76bf0dbeba61683320a48f1aac887360a8df0 MATIC0.0005808663673.000001896
0x43ee3f1f68388e2741d8195c9049384cda48b2ca644fcbc43dd9bf4395b1d424Start Lottery270268322022-07-04 9:10:251 day 10 hrs ago0x6456be06d125c0b7f661e6e09e695af4d59d58d1 IN  0xe25f76bf0dbeba61683320a48f1aac887360a8df0 MATIC0.0001490255.000000032
0x309364af3f4e12092794d71eff6c480860f5ce22bb180f2d6bea985533b2d79eClose Lottery270261342022-07-04 8:01:241 day 11 hrs ago0x6456be06d125c0b7f661e6e09e695af4d59d58d1 IN  0xe25f76bf0dbeba61683320a48f1aac887360a8df0 MATIC0.0007386900025.000000016
0xb4402b745c4ef9d107b31f3ca84dad00542d6764cf7c69b64fecfa2c3dbbc1f6Start Lottery270240002022-07-04 4:31:011 day 14 hrs ago0x6456be06d125c0b7f661e6e09e695af4d59d58d1 IN  0xe25f76bf0dbeba61683320a48f1aac887360a8df0 MATIC0.00590783834914.549999998
0xec221cb11b04a153c594bb6f3a04a95eafbfb98a9bfabcc8085996ec145e6076Draw Final Numbe...270237942022-07-04 4:08:271 day 15 hrs ago0x6456be06d125c0b7f661e6e09e695af4d59d58d1 IN  0xe25f76bf0dbeba61683320a48f1aac887360a8df0 MATIC0.000313110
0x2d2d7c498cb6e9a7a02b561bc878af3097f7b5fa2f9053e516ea8fa2e54a2bc2Draw Final Numbe...270221442022-07-04 1:23:521 day 18 hrs ago0x6456be06d125c0b7f661e6e09e695af4d59d58d1 IN  0xe25f76bf0dbeba61683320a48f1aac887360a8df0 MATIC0.0015058437387.777234706
0x6eae8d01e6432aafc3fa759132cebc1cb7517bf0fcd9e45adf3dd90a791dcef7Close Lottery270209282022-07-03 23:20:531 day 20 hrs ago0x6456be06d125c0b7f661e6e09e695af4d59d58d1 IN  0xe25f76bf0dbeba61683320a48f1aac887360a8df0 MATIC0.00031803832110.24872136
0x7a858f74a0f163b458ecfd0221668f0fe76820f7cadb60d9ea4b1793ebf761f2Close Lottery270204802022-07-03 22:32:461 day 20 hrs ago0x6456be06d125c0b7f661e6e09e695af4d59d58d1 IN  0xe25f76bf0dbeba61683320a48f1aac887360a8df0 MATIC0.0014120274449.557645594
0xb9bda8c12117e7089bc8a43450418da7c7c5f9b9faea15decfb39a745130507eStart Lottery270198142022-07-03 21:10:251 day 22 hrs ago0x6456be06d125c0b7f661e6e09e695af4d59d58d1 IN  0xe25f76bf0dbeba61683320a48f1aac887360a8df0 MATIC0.00073484588224.655121036
0xefc00462ebf54075608d0f765a84d1867569a926652790039f49bb1444fe74d7Draw Final Numbe...270197902022-07-03 21:08:251 day 22 hrs ago0x6456be06d125c0b7f661e6e09e695af4d59d58d1 IN  0xe25f76bf0dbeba61683320a48f1aac887360a8df0 MATIC0.00137013444743.760282576
0xdae6da8fca8292eca011daf69e1cb8c82fffbda3a529ca4542bac04e9615783fStart Lottery270195202022-07-03 20:29:511 day 22 hrs ago0x6456be06d125c0b7f661e6e09e695af4d59d58d1 IN  0xe25f76bf0dbeba61683320a48f1aac887360a8df0 MATIC0.00032834904511.016575942
0x0ad1c23bc4fcf67f726077f344a9e65e10af21195a61b148e2b9fcad7d942023Draw Final Numbe...270193912022-07-03 20:08:231 day 23 hrs ago0x6456be06d125c0b7f661e6e09e695af4d59d58d1 IN  0xe25f76bf0dbeba61683320a48f1aac887360a8df0 MATIC0.00034492899211.016575942
0x099cabdf8d9693fd8f1aa3ad6af99e08817b616a98ad4c71eb3311785056a736Start Lottery270190732022-07-03 19:41:491 day 23 hrs ago0x6456be06d125c0b7f661e6e09e695af4d59d58d1 IN  0xe25f76bf0dbeba61683320a48f1aac887360a8df0 MATIC0.00356948448.791032346
0x5714931e2ffb752afdc628f3826593a57d07c2228f926da51e764abe2089271eDraw Final Numbe...270188652022-07-03 19:08:252 days 16 mins ago0x6456be06d125c0b7f661e6e09e695af4d59d58d1 IN  0xe25f76bf0dbeba61683320a48f1aac887360a8df0 MATIC0.0018834679059.727551132
0x1631e19f2128c2ef50c782b5363efd5253fb25246517c39865401a1d7c743dc1Close Lottery270168192022-07-03 15:01:342 days 4 hrs ago0x6456be06d125c0b7f661e6e09e695af4d59d58d1 IN  0xe25f76bf0dbeba61683320a48f1aac887360a8df0 MATIC0.00952336369864.461165702
0xe5b30819419fc329af4e96881a954d1f346067b97b5c340ceb29416b07465d1fStart Lottery270163872022-07-03 14:10:282 days 5 hrs ago0x6456be06d125c0b7f661e6e09e695af4d59d58d1 IN  0xe25f76bf0dbeba61683320a48f1aac887360a8df0 MATIC0.02785224422768.597362792
0x9227fea3d79a3124f83b5d7604283b26b027bedcb9c2bdcf7cb15a69cfc66ddaDraw Final Numbe...270163642022-07-03 14:08:322 days 5 hrs ago0x6456be06d125c0b7f661e6e09e695af4d59d58d1 IN  0xe25f76bf0dbeba61683320a48f1aac887360a8df0 MATIC0.013146933867.9
[ Download CSV Export 
Parent Txn Hash Block From To Value
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
PancakeSwapLottery

Compiler Version
v0.8.4+commit.c7e474f2

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 9 : PancakeSwapLottery.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
pragma abicoder v2;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "./interfaces/IRandomNumberGenerator.sol";
import "./interfaces/IPancakeSwapLottery.sol";

/** @title PancakeSwap Lottery.
 * @notice It is a contract for a lottery system using
 * randomness provided externally.
 */
contract PancakeSwapLottery is ReentrancyGuard, IPancakeSwapLottery, Ownable {
    using SafeERC20 for IERC20;

    address public injectorAddress;
    address public operatorAddress;
    address public treasuryAddress;

    uint256 public currentLotteryId;
    uint256 public currentTicketId;

    uint256 public maxNumberTicketsPerBuyOrClaim = 100;

    uint256 public maxPriceTicketInCake = 50 ether;
    uint256 public minPriceTicketInCake = 0.005 ether;

    uint256 public pendingInjectionNextLottery;

    uint256 public constant MIN_DISCOUNT_DIVISOR = 300;
    uint256 public constant MIN_LENGTH_LOTTERY = 5 minutes; // 4 hours
    uint256 public constant MAX_LENGTH_LOTTERY = 4 days + 5 minutes; // 4 days
    uint256 public constant MAX_TREASURY_FEE = 3000; // 30%

    IERC20 public cakeToken;
    IRandomNumberGenerator public randomGenerator;

    enum Status {
        Pending,
        Open,
        Close,
        Claimable
    }

    struct Lottery {
        Status status;
        uint256 startTime;
        uint256 endTime;
        uint256 priceTicketInCake;
        uint256 discountDivisor;
        uint256[6] rewardsBreakdown; // 0: 1 matching number // 5: 6 matching numbers
        uint256 treasuryFee; // 500: 5% // 200: 2% // 50: 0.5%
        uint256[6] cakePerBracket;
        uint256[6] countWinnersPerBracket;
        uint256 firstTicketId;
        uint256 firstTicketIdNextLottery;
        uint256 amountCollectedInCake;
        uint32 finalNumber;
    }

    struct Ticket {
        uint32 number;
        address owner;
    }

    // Mapping are cheaper than arrays
    mapping(uint256 => Lottery) private _lotteries;
    mapping(uint256 => Ticket) private _tickets;

    // Bracket calculator is used for verifying claims for ticket prizes
    mapping(uint32 => uint32) private _bracketCalculator;

    // Keeps track of number of ticket per unique combination for each lotteryId
    mapping(uint256 => mapping(uint32 => uint256)) private _numberTicketsPerLotteryId;

    // Keep track of user ticket ids for a given lotteryId
    mapping(address => mapping(uint256 => uint256[])) private _userTicketIdsPerLotteryId;

    modifier notContract() {
        require(!_isContract(msg.sender), "Contract not allowed");
        require(msg.sender == tx.origin, "Proxy contract not allowed");
        _;
    }

    modifier onlyOperator() {
        require(msg.sender == operatorAddress, "Not operator");
        _;
    }

    modifier onlyOwnerOrInjector() {
        require((msg.sender == owner()) || (msg.sender == injectorAddress), "Not owner or injector");
        _;
    }

    event AdminTokenRecovery(address token, uint256 amount);
    event LotteryClose(uint256 indexed lotteryId, uint256 firstTicketIdNextLottery);
    event LotteryInjection(uint256 indexed lotteryId, uint256 injectedAmount);
    event LotteryOpen(
        uint256 indexed lotteryId,
        uint256 startTime,
        uint256 endTime,
        uint256 priceTicketInCake,
        uint256 firstTicketId,
        uint256 injectedAmount
    );
    event LotteryNumberDrawn(uint256 indexed lotteryId, uint256 finalNumber, uint256 countWinningTickets);
    event NewOperatorAndTreasuryAndInjectorAddresses(address operator, address treasury, address injector);
    event NewRandomGenerator(address indexed randomGenerator);
    event TicketsPurchase(address indexed buyer, uint256 indexed lotteryId, uint256 numberTickets);
    event TicketsClaim(address indexed claimer, uint256 amount, uint256 indexed lotteryId, uint256 numberTickets);

    /**
     * @notice Constructor
     * @dev RandomNumberGenerator must be deployed prior to this contract
     * @param _cakeTokenAddress: address of the CAKE token
     * @param _randomGeneratorAddress: address of the RandomGenerator contract used to work with ChainLink VRF
     */
    constructor(address _cakeTokenAddress, address _randomGeneratorAddress) {
        cakeToken = IERC20(_cakeTokenAddress);
        randomGenerator = IRandomNumberGenerator(_randomGeneratorAddress);

        // Initializes a mapping
        _bracketCalculator[0] = 1;
        _bracketCalculator[1] = 11;
        _bracketCalculator[2] = 111;
        _bracketCalculator[3] = 1111;
        _bracketCalculator[4] = 11111;
        _bracketCalculator[5] = 111111;
    }

    /**
     * @notice Buy tickets for the current lottery
     * @param _lotteryId: lotteryId
     * @param _ticketNumbers: array of ticket numbers between 1,000,000 and 1,999,999
     * @dev Callable by users
     */
    function buyTickets(uint256 _lotteryId, uint32[] calldata _ticketNumbers)
        external
        override
        notContract
        nonReentrant
    {
        require(_ticketNumbers.length != 0, "No ticket specified");
        require(_ticketNumbers.length <= maxNumberTicketsPerBuyOrClaim, "Too many tickets");

        require(_lotteries[_lotteryId].status == Status.Open, "Lottery is not open");
        require(block.timestamp < _lotteries[_lotteryId].endTime, "Lottery is over");

        // Calculate number of CAKE to this contract
        uint256 amountCakeToTransfer = _calculateTotalPriceForBulkTickets(
            _lotteries[_lotteryId].discountDivisor,
            _lotteries[_lotteryId].priceTicketInCake,
            _ticketNumbers.length
        );

        // Transfer cake tokens to this contract
        cakeToken.safeTransferFrom(address(msg.sender), address(this), amountCakeToTransfer);

        // Increment the total amount collected for the lottery round
        _lotteries[_lotteryId].amountCollectedInCake += amountCakeToTransfer;

        for (uint256 i = 0; i < _ticketNumbers.length; i++) {
            uint32 thisTicketNumber = _ticketNumbers[i];

            require((thisTicketNumber >= 1000000) && (thisTicketNumber <= 1999999), "Outside range");

            _numberTicketsPerLotteryId[_lotteryId][1 + (thisTicketNumber % 10)]++;
            _numberTicketsPerLotteryId[_lotteryId][11 + (thisTicketNumber % 100)]++;
            _numberTicketsPerLotteryId[_lotteryId][111 + (thisTicketNumber % 1000)]++;
            _numberTicketsPerLotteryId[_lotteryId][1111 + (thisTicketNumber % 10000)]++;
            _numberTicketsPerLotteryId[_lotteryId][11111 + (thisTicketNumber % 100000)]++;
            _numberTicketsPerLotteryId[_lotteryId][111111 + (thisTicketNumber % 1000000)]++;

            _userTicketIdsPerLotteryId[msg.sender][_lotteryId].push(currentTicketId);

            _tickets[currentTicketId] = Ticket({number: thisTicketNumber, owner: msg.sender});

            // Increase lottery ticket number
            currentTicketId++;
        }

        emit TicketsPurchase(msg.sender, _lotteryId, _ticketNumbers.length);
    }

    /**
     * @notice Claim a set of winning tickets for a lottery
     * @param _lotteryId: lottery id
     * @param _ticketIds: array of ticket ids
     * @param _brackets: array of brackets for the ticket ids
     * @dev Callable by users only, not contract!
     */
    function claimTickets(
        uint256 _lotteryId,
        uint256[] calldata _ticketIds,
        uint32[] calldata _brackets
    ) external override notContract nonReentrant {
        require(_ticketIds.length == _brackets.length, "Not same length");
        require(_ticketIds.length != 0, "Length must be >0");
        require(_ticketIds.length <= maxNumberTicketsPerBuyOrClaim, "Too many tickets");
        require(_lotteries[_lotteryId].status == Status.Claimable, "Lottery not claimable");

        // Initializes the rewardInCakeToTransfer
        uint256 rewardInCakeToTransfer;

        for (uint256 i = 0; i < _ticketIds.length; i++) {
            require(_brackets[i] < 6, "Bracket out of range"); // Must be between 0 and 5

            uint256 thisTicketId = _ticketIds[i];

            require(_lotteries[_lotteryId].firstTicketIdNextLottery > thisTicketId, "TicketId too high");
            require(_lotteries[_lotteryId].firstTicketId <= thisTicketId, "TicketId too low");
            require(msg.sender == _tickets[thisTicketId].owner, "Not the owner");

            // Update the lottery ticket owner to 0x address
            _tickets[thisTicketId].owner = address(0);

            uint256 rewardForTicketId = _calculateRewardsForTicketId(_lotteryId, thisTicketId, _brackets[i]);

            // Check user is claiming the correct bracket
            require(rewardForTicketId != 0, "No prize for this bracket");

            if (_brackets[i] != 5) {
                require(
                    _calculateRewardsForTicketId(_lotteryId, thisTicketId, _brackets[i] + 1) == 0,
                    "Bracket must be higher"
                );
            }

            // Increment the reward to transfer
            rewardInCakeToTransfer += rewardForTicketId;
        }

        // Transfer money to msg.sender
        cakeToken.safeTransfer(msg.sender, rewardInCakeToTransfer);

        emit TicketsClaim(msg.sender, rewardInCakeToTransfer, _lotteryId, _ticketIds.length);
    }

    /**
     * @notice Close lottery
     * @param _lotteryId: lottery id
     * @dev Callable by operator
     */
    function closeLottery(uint256 _lotteryId) external override onlyOperator nonReentrant {
        require(_lotteries[_lotteryId].status == Status.Open, "Lottery not open");
        require(block.timestamp > _lotteries[_lotteryId].endTime, "Lottery not over");
        _lotteries[_lotteryId].firstTicketIdNextLottery = currentTicketId;

        // Request a random number from the generator based on a seed
        randomGenerator.getRandomNumber(uint256(keccak256(abi.encodePacked(_lotteryId, currentTicketId))));

        _lotteries[_lotteryId].status = Status.Close;

        emit LotteryClose(_lotteryId, currentTicketId);
    }

    /**
     * @notice Draw the final number, calculate reward in CAKE per group, and make lottery claimable
     * @param _lotteryId: lottery id
     * @param _autoInjection: reinjects funds into next lottery (vs. withdrawing all)
     * @dev Callable by operator
     */
    function drawFinalNumberAndMakeLotteryClaimable(uint256 _lotteryId, bool _autoInjection)
        external
        override
        onlyOperator
        nonReentrant
    {
        require(_lotteries[_lotteryId].status == Status.Close, "Lottery not close");
        require(_lotteryId == randomGenerator.viewLatestLotteryId(), "Numbers not drawn");

        // Calculate the finalNumber based on the randomResult generated by ChainLink's fallback
        uint32 finalNumber = randomGenerator.viewRandomResult();

        // Initialize a number to count addresses in the previous bracket
        uint256 numberAddressesInPreviousBracket;

        // Calculate the amount to share post-treasury fee
        uint256 amountToShareToWinners = (
            ((_lotteries[_lotteryId].amountCollectedInCake) * (10000 - _lotteries[_lotteryId].treasuryFee))
        ) / 10000;

        // Initializes the amount to withdraw to treasury
        uint256 amountToWithdrawToTreasury;

        // Calculate prizes in CAKE for each bracket by starting from the highest one
        for (uint32 i = 0; i < 6; i++) {
            uint32 j = 5 - i;
            uint32 transformedWinningNumber = _bracketCalculator[j] + (finalNumber % (uint32(10)**(j + 1)));

            _lotteries[_lotteryId].countWinnersPerBracket[j] =
                _numberTicketsPerLotteryId[_lotteryId][transformedWinningNumber] -
                numberAddressesInPreviousBracket;

            // A. If number of users for this _bracket number is superior to 0
            if (
                (_numberTicketsPerLotteryId[_lotteryId][transformedWinningNumber] - numberAddressesInPreviousBracket) !=
                0
            ) {
                // B. If rewards at this bracket are > 0, calculate, else, report the numberAddresses from previous bracket
                if (_lotteries[_lotteryId].rewardsBreakdown[j] != 0) {
                    _lotteries[_lotteryId].cakePerBracket[j] =
                        ((_lotteries[_lotteryId].rewardsBreakdown[j] * amountToShareToWinners) /
                            (_numberTicketsPerLotteryId[_lotteryId][transformedWinningNumber] -
                                numberAddressesInPreviousBracket)) /
                        10000;

                    // Update numberAddressesInPreviousBracket
                    numberAddressesInPreviousBracket = _numberTicketsPerLotteryId[_lotteryId][transformedWinningNumber];
                }
                // A. No CAKE to distribute, they are added to the amount to withdraw to treasury address
            } else {
                _lotteries[_lotteryId].cakePerBracket[j] = 0;

                amountToWithdrawToTreasury +=
                    (_lotteries[_lotteryId].rewardsBreakdown[j] * amountToShareToWinners) /
                    10000;
            }
        }

        // Update internal statuses for lottery
        _lotteries[_lotteryId].finalNumber = finalNumber;
        _lotteries[_lotteryId].status = Status.Claimable;

        if (_autoInjection) {
            pendingInjectionNextLottery = amountToWithdrawToTreasury;
            amountToWithdrawToTreasury = 0;
        }

        amountToWithdrawToTreasury += (_lotteries[_lotteryId].amountCollectedInCake - amountToShareToWinners);

        // Transfer CAKE to treasury address
        cakeToken.safeTransfer(treasuryAddress, amountToWithdrawToTreasury);

        emit LotteryNumberDrawn(currentLotteryId, finalNumber, numberAddressesInPreviousBracket);
    }

    /**
     * @notice Change the random generator
     * @dev The calls to functions are used to verify the new generator implements them properly.
     * It is necessary to wait for the VRF response before starting a round.
     * Callable only by the contract owner
     * @param _randomGeneratorAddress: address of the random generator
     */
    function changeRandomGenerator(address _randomGeneratorAddress) external onlyOwner {
        require(
            (currentLotteryId == 0) || (_lotteries[currentLotteryId].status == Status.Claimable),
            "Lottery not in claimable"
        );

        // Request a random number from the generator based on a seed
        IRandomNumberGenerator(_randomGeneratorAddress).getRandomNumber(
            uint256(keccak256(abi.encodePacked(currentLotteryId, currentTicketId)))
        );

        // Calculate the finalNumber based on the randomResult generated by ChainLink's fallback
        IRandomNumberGenerator(_randomGeneratorAddress).viewRandomResult();

        randomGenerator = IRandomNumberGenerator(_randomGeneratorAddress);

        emit NewRandomGenerator(_randomGeneratorAddress);
    }

    /**
     * @notice Inject funds
     * @param _lotteryId: lottery id
     * @param _amount: amount to inject in CAKE token
     * @dev Callable by owner or injector address
     */
    function injectFunds(uint256 _lotteryId, uint256 _amount) external override onlyOwnerOrInjector {
        require(_lotteries[_lotteryId].status == Status.Open, "Lottery not open");

        cakeToken.safeTransferFrom(address(msg.sender), address(this), _amount);
        _lotteries[_lotteryId].amountCollectedInCake += _amount;

        emit LotteryInjection(_lotteryId, _amount);
    }

    /**
     * @notice Start the lottery
     * @dev Callable by operator
     * @param _endTime: endTime of the lottery
     * @param _priceTicketInCake: price of a ticket in CAKE
     * @param _discountDivisor: the divisor to calculate the discount magnitude for bulks
     * @param _rewardsBreakdown: breakdown of rewards per bracket (must sum to 10,000)
     * @param _treasuryFee: treasury fee (10,000 = 100%, 100 = 1%)
     */
    function startLottery(
        uint256 _endTime,
        uint256 _priceTicketInCake,
        uint256 _discountDivisor,
        uint256[6] calldata _rewardsBreakdown,
        uint256 _treasuryFee
    ) external override onlyOperator {
        require(
            (currentLotteryId == 0) || (_lotteries[currentLotteryId].status == Status.Claimable),
            "Not time to start lottery"
        );

        require(
            ((_endTime - block.timestamp) > MIN_LENGTH_LOTTERY) && ((_endTime - block.timestamp) < MAX_LENGTH_LOTTERY),
            "Lottery length outside of range"
        );

        require(
            (_priceTicketInCake >= minPriceTicketInCake) && (_priceTicketInCake <= maxPriceTicketInCake),
            "Outside of limits"
        );

        require(_discountDivisor >= MIN_DISCOUNT_DIVISOR, "Discount divisor too low");
        require(_treasuryFee <= MAX_TREASURY_FEE, "Treasury fee too high");

        require(
            (_rewardsBreakdown[0] +
                _rewardsBreakdown[1] +
                _rewardsBreakdown[2] +
                _rewardsBreakdown[3] +
                _rewardsBreakdown[4] +
                _rewardsBreakdown[5]) == 10000,
            "Rewards must equal 10000"
        );

        currentLotteryId++;

        _lotteries[currentLotteryId] = Lottery({
            status: Status.Open,
            startTime: block.timestamp,
            endTime: _endTime,
            priceTicketInCake: _priceTicketInCake,
            discountDivisor: _discountDivisor,
            rewardsBreakdown: _rewardsBreakdown,
            treasuryFee: _treasuryFee,
            cakePerBracket: [uint256(0), uint256(0), uint256(0), uint256(0), uint256(0), uint256(0)],
            countWinnersPerBracket: [uint256(0), uint256(0), uint256(0), uint256(0), uint256(0), uint256(0)],
            firstTicketId: currentTicketId,
            firstTicketIdNextLottery: currentTicketId,
            amountCollectedInCake: pendingInjectionNextLottery,
            finalNumber: 0
        });

        emit LotteryOpen(
            currentLotteryId,
            block.timestamp,
            _endTime,
            _priceTicketInCake,
            currentTicketId,
            pendingInjectionNextLottery
        );

        pendingInjectionNextLottery = 0;
    }

    /**
     * @notice It allows the admin to recover wrong tokens sent to the contract
     * @param _tokenAddress: the address of the token to withdraw
     * @param _tokenAmount: the number of token amount to withdraw
     * @dev Only callable by owner.
     */
    function recoverWrongTokens(address _tokenAddress, uint256 _tokenAmount) external onlyOwner {
        require(_tokenAddress != address(cakeToken), "Cannot be CAKE token");

        IERC20(_tokenAddress).safeTransfer(address(msg.sender), _tokenAmount);

        emit AdminTokenRecovery(_tokenAddress, _tokenAmount);
    }

    /**
     * @notice Set CAKE price ticket upper/lower limit
     * @dev Only callable by owner
     * @param _minPriceTicketInCake: minimum price of a ticket in CAKE
     * @param _maxPriceTicketInCake: maximum price of a ticket in CAKE
     */
    function setMinAndMaxTicketPriceInCake(uint256 _minPriceTicketInCake, uint256 _maxPriceTicketInCake)
        external
        onlyOwner
    {
        require(_minPriceTicketInCake <= _maxPriceTicketInCake, "minPrice must be < maxPrice");

        minPriceTicketInCake = _minPriceTicketInCake;
        maxPriceTicketInCake = _maxPriceTicketInCake;
    }

    /**
     * @notice Set max number of tickets
     * @dev Only callable by owner
     */
    function setMaxNumberTicketsPerBuy(uint256 _maxNumberTicketsPerBuy) external onlyOwner {
        require(_maxNumberTicketsPerBuy != 0, "Must be > 0");
        maxNumberTicketsPerBuyOrClaim = _maxNumberTicketsPerBuy;
    }

    /**
     * @notice Set operator, treasury, and injector addresses
     * @dev Only callable by owner
     * @param _operatorAddress: address of the operator
     * @param _treasuryAddress: address of the treasury
     * @param _injectorAddress: address of the injector
     */
    function setOperatorAndTreasuryAndInjectorAddresses(
        address _operatorAddress,
        address _treasuryAddress,
        address _injectorAddress
    ) external onlyOwner {
        require(_operatorAddress != address(0), "Cannot be zero address");
        require(_treasuryAddress != address(0), "Cannot be zero address");
        require(_injectorAddress != address(0), "Cannot be zero address");

        operatorAddress = _operatorAddress;
        treasuryAddress = _treasuryAddress;
        injectorAddress = _injectorAddress;

        emit NewOperatorAndTreasuryAndInjectorAddresses(_operatorAddress, _treasuryAddress, _injectorAddress);
    }

    /**
     * @notice Calculate price of a set of tickets
     * @param _discountDivisor: divisor for the discount
     * @param _priceTicket price of a ticket (in CAKE)
     * @param _numberTickets number of tickets to buy
     */
    function calculateTotalPriceForBulkTickets(
        uint256 _discountDivisor,
        uint256 _priceTicket,
        uint256 _numberTickets
    ) external pure returns (uint256) {
        require(_discountDivisor >= MIN_DISCOUNT_DIVISOR, "Must be >= MIN_DISCOUNT_DIVISOR");
        require(_numberTickets != 0, "Number of tickets must be > 0");

        return _calculateTotalPriceForBulkTickets(_discountDivisor, _priceTicket, _numberTickets);
    }

    /**
     * @notice View current lottery id
     */
    function viewCurrentLotteryId() external view override returns (uint256) {
        return currentLotteryId;
    }

    /**
     * @notice View lottery information
     * @param _lotteryId: lottery id
     */
    function viewLottery(uint256 _lotteryId) external view returns (Lottery memory) {
        return _lotteries[_lotteryId];
    }

    /**
     * @notice View ticker statuses and numbers for an array of ticket ids
     * @param _ticketIds: array of _ticketId
     */
    function viewNumbersAndStatusesForTicketIds(uint256[] calldata _ticketIds)
        external
        view
        returns (uint32[] memory, bool[] memory)
    {
        uint256 length = _ticketIds.length;
        uint32[] memory ticketNumbers = new uint32[](length);
        bool[] memory ticketStatuses = new bool[](length);

        for (uint256 i = 0; i < length; i++) {
            ticketNumbers[i] = _tickets[_ticketIds[i]].number;
            if (_tickets[_ticketIds[i]].owner == address(0)) {
                ticketStatuses[i] = true;
            } else {
                ticketStatuses[i] = false;
            }
        }

        return (ticketNumbers, ticketStatuses);
    }

    /**
     * @notice View rewards for a given ticket, providing a bracket, and lottery id
     * @dev Computations are mostly offchain. This is used to verify a ticket!
     * @param _lotteryId: lottery id
     * @param _ticketId: ticket id
     * @param _bracket: bracket for the ticketId to verify the claim and calculate rewards
     */
    function viewRewardsForTicketId(
        uint256 _lotteryId,
        uint256 _ticketId,
        uint32 _bracket
    ) external view returns (uint256) {
        // Check lottery is in claimable status
        if (_lotteries[_lotteryId].status != Status.Claimable) {
            return 0;
        }

        // Check ticketId is within range
        if (
            (_lotteries[_lotteryId].firstTicketIdNextLottery < _ticketId) &&
            (_lotteries[_lotteryId].firstTicketId >= _ticketId)
        ) {
            return 0;
        }

        return _calculateRewardsForTicketId(_lotteryId, _ticketId, _bracket);
    }

    /**
     * @notice View user ticket ids, numbers, and statuses of user for a given lottery
     * @param _user: user address
     * @param _lotteryId: lottery id
     * @param _cursor: cursor to start where to retrieve the tickets
     * @param _size: the number of tickets to retrieve
     */
    function viewUserInfoForLotteryId(
        address _user,
        uint256 _lotteryId,
        uint256 _cursor,
        uint256 _size
    )
        external
        view
        override
        returns (
            uint256[] memory,
            uint32[] memory,
            bool[] memory,
            uint256
        )
    {
        uint256 length = _size;
        uint256 numberTicketsBoughtAtLotteryId = _userTicketIdsPerLotteryId[_user][_lotteryId].length;

        if (length > (numberTicketsBoughtAtLotteryId - _cursor)) {
            length = numberTicketsBoughtAtLotteryId - _cursor;
        }

        uint256[] memory lotteryTicketIds = new uint256[](length);
        uint32[] memory ticketNumbers = new uint32[](length);
        bool[] memory ticketStatuses = new bool[](length);

        for (uint256 i = 0; i < length; i++) {
            lotteryTicketIds[i] = _userTicketIdsPerLotteryId[_user][_lotteryId][i + _cursor];
            ticketNumbers[i] = _tickets[lotteryTicketIds[i]].number;

            // True = ticket claimed
            if (_tickets[lotteryTicketIds[i]].owner == address(0)) {
                ticketStatuses[i] = true;
            } else {
                // ticket not claimed (includes the ones that cannot be claimed)
                ticketStatuses[i] = false;
            }
        }

        return (lotteryTicketIds, ticketNumbers, ticketStatuses, _cursor + length);
    }

    /**
     * @notice Calculate rewards for a given ticket
     * @param _lotteryId: lottery id
     * @param _ticketId: ticket id
     * @param _bracket: bracket for the ticketId to verify the claim and calculate rewards
     */
    function _calculateRewardsForTicketId(
        uint256 _lotteryId,
        uint256 _ticketId,
        uint32 _bracket
    ) internal view returns (uint256) {
        // Retrieve the winning number combination
        uint32 winningTicketNumber = _lotteries[_lotteryId].finalNumber;

        // Retrieve the user number combination from the ticketId
        uint32 userNumber = _tickets[_ticketId].number;

        // Apply transformation to verify the claim provided by the user is true
        uint32 transformedWinningNumber = _bracketCalculator[_bracket] +
            (winningTicketNumber % (uint32(10)**(_bracket + 1)));

        uint32 transformedUserNumber = _bracketCalculator[_bracket] + (userNumber % (uint32(10)**(_bracket + 1)));

        // Confirm that the two transformed numbers are the same, if not throw
        if (transformedWinningNumber == transformedUserNumber) {
            return _lotteries[_lotteryId].cakePerBracket[_bracket];
        } else {
            return 0;
        }
    }

    /**
     * @notice Calculate final price for bulk of tickets
     * @param _discountDivisor: divisor for the discount (the smaller it is, the greater the discount is)
     * @param _priceTicket: price of a ticket
     * @param _numberTickets: number of tickets purchased
     */
    function _calculateTotalPriceForBulkTickets(
        uint256 _discountDivisor,
        uint256 _priceTicket,
        uint256 _numberTickets
    ) internal pure returns (uint256) {
        return (_priceTicket * _numberTickets * (_discountDivisor + 1 - _numberTickets)) / _discountDivisor;
    }

    /**
     * @notice Check if an address is a contract
     */
    function _isContract(address _addr) internal view returns (bool) {
        uint256 size;
        assembly {
            size := extcodesize(_addr)
        }
        return size > 0;
    }
}

File 2 of 9 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

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

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

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

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

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

File 3 of 9 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;

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

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

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

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

        _;

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

File 4 of 9 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

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

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

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

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

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

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

File 5 of 9 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    function safeTransfer(
        IERC20 token,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(
        IERC20 token,
        address from,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 newAllowance = token.allowance(address(this), spender) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            uint256 newAllowance = oldAllowance - value;
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) {
            // Return data is optional
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

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

interface IRandomNumberGenerator {
    /**
     * Requests randomness from a user-provided seed
     */
    function getRandomNumber(uint256 _seed) external;

    /**
     * View latest lotteryId numbers
     */
    function viewLatestLotteryId() external view returns (uint256);

    /**
     * Views random result
     */
    function viewRandomResult() external view returns (uint32);
}

File 7 of 9 : IPancakeSwapLottery.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0;

interface IPancakeSwapLottery {
    /**
     * @notice Buy tickets for the current lottery
     * @param _lotteryId: lotteryId
     * @param _ticketNumbers: array of ticket numbers between 1,000,000 and 1,999,999
     * @dev Callable by users
     */
    function buyTickets(uint256 _lotteryId, uint32[] calldata _ticketNumbers) external;

    /**
     * @notice Claim a set of winning tickets for a lottery
     * @param _lotteryId: lottery id
     * @param _ticketIds: array of ticket ids
     * @param _brackets: array of brackets for the ticket ids
     * @dev Callable by users only, not contract!
     */
    function claimTickets(
        uint256 _lotteryId,
        uint256[] calldata _ticketIds,
        uint32[] calldata _brackets
    ) external;

    /**
     * @notice Close lottery
     * @param _lotteryId: lottery id
     * @dev Callable by operator
     */
    function closeLottery(uint256 _lotteryId) external;

    /**
     * @notice Draw the final number, calculate reward in CAKE per group, and make lottery claimable
     * @param _lotteryId: lottery id
     * @param _autoInjection: reinjects funds into next lottery (vs. withdrawing all)
     * @dev Callable by operator
     */
    function drawFinalNumberAndMakeLotteryClaimable(uint256 _lotteryId, bool _autoInjection) external;

    /**
     * @notice Inject funds
     * @param _lotteryId: lottery id
     * @param _amount: amount to inject in CAKE token
     * @dev Callable by operator
     */
    function injectFunds(uint256 _lotteryId, uint256 _amount) external;

    /**
     * @notice Start the lottery
     * @dev Callable by operator
     * @param _endTime: endTime of the lottery
     * @param _priceTicketInCake: price of a ticket in CAKE
     * @param _discountDivisor: the divisor to calculate the discount magnitude for bulks
     * @param _rewardsBreakdown: breakdown of rewards per bracket (must sum to 10,000)
     * @param _treasuryFee: treasury fee (10,000 = 100%, 100 = 1%)
     */
    function startLottery(
        uint256 _endTime,
        uint256 _priceTicketInCake,
        uint256 _discountDivisor,
        uint256[6] calldata _rewardsBreakdown,
        uint256 _treasuryFee
    ) external;

    /**
     * @notice View current lottery id
     */
    function viewCurrentLotteryId() external returns (uint256);

    /**
     * @notice View user ticket ids, numbers, and statuses of user for a given lottery
     * @param _user: user address
     * @param _lotteryId: lottery id
     * @param _cursor: cursor to start where to retrieve the tickets
     * @param _size: the number of tickets to retrieve
     */
    function viewUserInfoForLotteryId(
        address _user,
        uint256 _lotteryId,
        uint256 _cursor,
        uint256 _size
    )
        external
        view
        returns (
            uint256[] memory,
            uint32[] memory,
            bool[] memory,
            uint256
        );
}

File 8 of 9 : 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 9 of 9 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

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

Contract ABI

[{"inputs":[{"internalType":"address","name":"_cakeTokenAddress","type":"address"},{"internalType":"address","name":"_randomGeneratorAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"AdminTokenRecovery","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"lotteryId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"firstTicketIdNextLottery","type":"uint256"}],"name":"LotteryClose","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"lotteryId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"injectedAmount","type":"uint256"}],"name":"LotteryInjection","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"lotteryId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"finalNumber","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"countWinningTickets","type":"uint256"}],"name":"LotteryNumberDrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"lotteryId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"priceTicketInCake","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"firstTicketId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"injectedAmount","type":"uint256"}],"name":"LotteryOpen","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"address","name":"treasury","type":"address"},{"indexed":false,"internalType":"address","name":"injector","type":"address"}],"name":"NewOperatorAndTreasuryAndInjectorAddresses","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"randomGenerator","type":"address"}],"name":"NewRandomGenerator","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"claimer","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"lotteryId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"numberTickets","type":"uint256"}],"name":"TicketsClaim","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"buyer","type":"address"},{"indexed":true,"internalType":"uint256","name":"lotteryId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"numberTickets","type":"uint256"}],"name":"TicketsPurchase","type":"event"},{"inputs":[],"name":"MAX_LENGTH_LOTTERY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_TREASURY_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_DISCOUNT_DIVISOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_LENGTH_LOTTERY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lotteryId","type":"uint256"},{"internalType":"uint32[]","name":"_ticketNumbers","type":"uint32[]"}],"name":"buyTickets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cakeToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_discountDivisor","type":"uint256"},{"internalType":"uint256","name":"_priceTicket","type":"uint256"},{"internalType":"uint256","name":"_numberTickets","type":"uint256"}],"name":"calculateTotalPriceForBulkTickets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_randomGeneratorAddress","type":"address"}],"name":"changeRandomGenerator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lotteryId","type":"uint256"},{"internalType":"uint256[]","name":"_ticketIds","type":"uint256[]"},{"internalType":"uint32[]","name":"_brackets","type":"uint32[]"}],"name":"claimTickets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lotteryId","type":"uint256"}],"name":"closeLottery","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"currentLotteryId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentTicketId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lotteryId","type":"uint256"},{"internalType":"bool","name":"_autoInjection","type":"bool"}],"name":"drawFinalNumberAndMakeLotteryClaimable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lotteryId","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"injectFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"injectorAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxNumberTicketsPerBuyOrClaim","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxPriceTicketInCake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minPriceTicketInCake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"operatorAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingInjectionNextLottery","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"randomGenerator","outputs":[{"internalType":"contract IRandomNumberGenerator","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"uint256","name":"_tokenAmount","type":"uint256"}],"name":"recoverWrongTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxNumberTicketsPerBuy","type":"uint256"}],"name":"setMaxNumberTicketsPerBuy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minPriceTicketInCake","type":"uint256"},{"internalType":"uint256","name":"_maxPriceTicketInCake","type":"uint256"}],"name":"setMinAndMaxTicketPriceInCake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operatorAddress","type":"address"},{"internalType":"address","name":"_treasuryAddress","type":"address"},{"internalType":"address","name":"_injectorAddress","type":"address"}],"name":"setOperatorAndTreasuryAndInjectorAddresses","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_endTime","type":"uint256"},{"internalType":"uint256","name":"_priceTicketInCake","type":"uint256"},{"internalType":"uint256","name":"_discountDivisor","type":"uint256"},{"internalType":"uint256[6]","name":"_rewardsBreakdown","type":"uint256[6]"},{"internalType":"uint256","name":"_treasuryFee","type":"uint256"}],"name":"startLottery","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"treasuryAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"viewCurrentLotteryId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lotteryId","type":"uint256"}],"name":"viewLottery","outputs":[{"components":[{"internalType":"enum PancakeSwapLottery.Status","name":"status","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"priceTicketInCake","type":"uint256"},{"internalType":"uint256","name":"discountDivisor","type":"uint256"},{"internalType":"uint256[6]","name":"rewardsBreakdown","type":"uint256[6]"},{"internalType":"uint256","name":"treasuryFee","type":"uint256"},{"internalType":"uint256[6]","name":"cakePerBracket","type":"uint256[6]"},{"internalType":"uint256[6]","name":"countWinnersPerBracket","type":"uint256[6]"},{"internalType":"uint256","name":"firstTicketId","type":"uint256"},{"internalType":"uint256","name":"firstTicketIdNextLottery","type":"uint256"},{"internalType":"uint256","name":"amountCollectedInCake","type":"uint256"},{"internalType":"uint32","name":"finalNumber","type":"uint32"}],"internalType":"struct PancakeSwapLottery.Lottery","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_ticketIds","type":"uint256[]"}],"name":"viewNumbersAndStatusesForTicketIds","outputs":[{"internalType":"uint32[]","name":"","type":"uint32[]"},{"internalType":"bool[]","name":"","type":"bool[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lotteryId","type":"uint256"},{"internalType":"uint256","name":"_ticketId","type":"uint256"},{"internalType":"uint32","name":"_bracket","type":"uint32"}],"name":"viewRewardsForTicketId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_lotteryId","type":"uint256"},{"internalType":"uint256","name":"_cursor","type":"uint256"},{"internalType":"uint256","name":"_size","type":"uint256"}],"name":"viewUserInfoForLotteryId","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint32[]","name":"","type":"uint32[]"},{"internalType":"bool[]","name":"","type":"bool[]"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

608060405260646007556802b5e3af16b18800006008556611c37937e080006009553480156200002e57600080fd5b5060405162003de338038062003de3833981016040819052620000519162000219565b60016000556200006133620001aa565b600b80546001600160a01b039384166001600160a01b0319918216178255600c805493909416921691909117909155600f6020527ff4803e074bd026baaf6ed2e288c9515f68c72fb7216eebdd7cae1718a53ec375805463ffffffff199081166001179091557f169f97de0d9a84d840042b17d3c6b9638b3d6fd9024c9eb0c7a306a17b49f88f805482169092179091557fa74ba3945261e09fde15ba3db55005b205e61eeb4ad811ac0faa2b315bffeead80548216606f1790557f45f76dafbbad695564362934e24d72eedc57f9fc1a65f39bca62176cc8296828805482166104571790557f367ccd2d0ac16bf7110a5dffe0801fdc9452a95a1adb7e1a12fe97dd3e9a4edd80548216612b6717905560056000527f6bda57492eba051cb4a12a1e19df47c9755d78165341d4009b1d09b3f361620480549091166201b20717905562000250565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b80516001600160a01b03811681146200021457600080fd5b919050565b600080604083850312156200022c578182fd5b6200023783620001fc565b91506200024760208401620001fc565b90509250929050565b613b8380620002606000396000f3fe608060405234801561001057600080fd5b50600436106102115760003560e01c806388303dbd11610125578063c4937ab9116100ad578063da7429f81161007c578063da7429f81461043b578063db19da0d1461044e578063dcbad90d14610458578063f2b3c8091461046b578063f2fde38b1461047457600080fd5b8063c4937ab9146103ef578063c5f956af14610402578063c914914f14610415578063da4ca0391461042857600080fd5b806398359fa1116100f457806398359fa1146103905780639c384653146103a35780639d8ca531146103b6578063b1829b82146103c9578063c38de539146103dc57600080fd5b806388303dbd146103385780638904bf2f1461034b5780638da5cb5b1461035e5780638fc3539a1461036f57600080fd5b806331feb565116101a85780636b873788116101775780636b8737881461030c5780636be4097c1461031f578063715018a6146103285780637cb583bd1461024257806380a061601461033057600080fd5b806331feb565146102d25780633f138d4b146102db578063471aeab4146102f0578063686465b81461030357600080fd5b80631f73664b116101e45780631f73664b1461028d5780631fe86c6b146102965780632423807a1461029f5780632e530cae146102bf57600080fd5b806305531eeb1461021657806307fb5a9c14610242578063127effb21461025957806312a9769d14610284575b600080fd5b6102296102243660046132a9565b610487565b6040516102399493929190613638565b60405180910390f35b61024b61012c81565b604051908152602001610239565b60035461026c906001600160a01b031681565b6040516001600160a01b039091168152602001610239565b61024b600a5481565b61024b60085481565b61024b60075481565b6102b26102ad36600461333d565b6107ff565b60405161023991906137cf565b61024b6102cd3660046134f6565b61097c565b61024b60095481565b6102ee6102e9366004613280565b610a11565b005b6102ee6102fe36600461345d565b610af3565b61024b60065481565b6102ee61031a36600461333d565b610c44565b61024b60055481565b6102ee610cae565b60055461024b565b6102ee6103463660046133e4565b610ce4565b600b5461026c906001600160a01b031681565b6001546001600160a01b031661026c565b61038261037d3660046132e1565b6112c5565b6040516102399291906136ac565b6102ee61039e366004613224565b6114e1565b60025461026c906001600160a01b031681565b6102ee6103c436600461333d565b6116e8565b6102ee6103d73660046134a9565b6118fe565b6102ee6103ea36600461342e565b611e04565b61024b6103fd36600461347e565b6123fc565b60045461026c906001600160a01b031681565b6102ee61042336600461336d565b6124a8565b6102ee61043636600461323e565b612a65565b6102ee61044936600461345d565b612b85565b61024b6205472c81565b600c5461026c906001600160a01b031681565b61024b610bb881565b6102ee610482366004613224565b612c0a565b6001600160a01b0384166000908152601160209081526040808320868452909152812054606091829182919085906104bf8882613a37565b8211156104d3576104d08882613a37565b91505b60008267ffffffffffffffff8111156104fc57634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015610525578160200160208202803683370190505b50905060008367ffffffffffffffff81111561055157634e487b7160e01b600052604160045260246000fd5b60405190808252806020026020018201604052801561057a578160200160208202803683370190505b50905060008467ffffffffffffffff8111156105a657634e487b7160e01b600052604160045260246000fd5b6040519080825280602002602001820160405280156105cf578160200160208202803683370190505b50905060005b858110156107d957601160008f6001600160a01b03166001600160a01b0316815260200190815260200160002060008e81526020019081526020016000208c8261061f9190613892565b8154811061063d57634e487b7160e01b600052603260045260246000fd5b906000526020600020015484828151811061066857634e487b7160e01b600052603260045260246000fd5b602002602001018181525050600e600085838151811061069857634e487b7160e01b600052603260045260246000fd5b6020026020010151815260200190815260200160002060000160009054906101000a900463ffffffff168382815181106106e257634e487b7160e01b600052603260045260246000fd5b602002602001019063ffffffff16908163ffffffff168152505060006001600160a01b0316600e600086848151811061072b57634e487b7160e01b600052603260045260246000fd5b60209081029190910181015182528101919091526040016000205464010000000090046001600160a01b0316141561079457600182828151811061077f57634e487b7160e01b600052603260045260246000fd5b911515602092830291909101909101526107c7565b60008282815181106107b657634e487b7160e01b600052603260045260246000fd5b911515602092830291909101909101525b806107d181613a9f565b9150506105d5565b508282826107e7888f613892565b98509850985098505050505050945094509450949050565b6108076130d3565b6000828152600d60205260409081902081516101a081019092528054829060ff16600381111561084757634e487b7160e01b600052602160045260246000fd5b600381111561086657634e487b7160e01b600052602160045260246000fd5b81526001820154602082015260028201546040808301919091526003830154606083015260048301546080830152805160c081019182905260a09092019190600584019060069082845b8154815260200190600101908083116108b0575050509183525050600b82015460208201526040805160c081018252910190600c830160068282826020028201915b8154815260200190600101908083116108f25750505091835250506040805160c081019182905260209092019190601284019060069082845b81548152602001906001019080831161092b5750505091835250506018820154602082015260198201546040820152601a8201546060820152601b9091015463ffffffff1660809091015292915050565b600060036000858152600d602052604090205460ff1660038111156109b157634e487b7160e01b600052602160045260246000fd5b146109be57506000610a0a565b6000848152600d6020526040902060190154831180156109ef57506000848152600d60205260409020601801548311155b156109fc57506000610a0a565b610a07848484612ca5565b90505b9392505050565b6001546001600160a01b03163314610a445760405162461bcd60e51b8152600401610a3b9061373d565b60405180910390fd5b600b546001600160a01b0383811691161415610a995760405162461bcd60e51b815260206004820152601460248201527321b0b73737ba1031329021a0a5a2903a37b5b2b760611b6044820152606401610a3b565b610aad6001600160a01b0383163383612dbe565b604080516001600160a01b0384168152602081018390527f74545154aac348a3eac92596bd1971957ca94795f4e954ec5f613b55fab78129910160405180910390a15050565b6001546001600160a01b0316331480610b1657506002546001600160a01b031633145b610b5a5760405162461bcd60e51b81526020600482015260156024820152742737ba1037bbb732b91037b91034b73532b1ba37b960591b6044820152606401610a3b565b60016000838152600d602052604090205460ff166003811115610b8d57634e487b7160e01b600052602160045260246000fd5b14610bcd5760405162461bcd60e51b815260206004820152601060248201526f2637ba3a32b93c903737ba1037b832b760811b6044820152606401610a3b565b600b54610be5906001600160a01b0316333084612e26565b6000828152600d60205260408120601a018054839290610c06908490613892565b909155505060405181815282907f1bbd659dd628a25f7ff2eabb69c74a56939c539728282275c1c9c1a2d3e340499060200160405180910390a25050565b6001546001600160a01b03163314610c6e5760405162461bcd60e51b8152600401610a3b9061373d565b80610ca95760405162461bcd60e51b815260206004820152600b60248201526a04d757374206265203e20360ac1b6044820152606401610a3b565b600755565b6001546001600160a01b03163314610cd85760405162461bcd60e51b8152600401610a3b9061373d565b610ce26000612e64565b565b333b15610d2a5760405162461bcd60e51b815260206004820152601460248201527310dbdb9d1c9858dd081b9bdd08185b1b1bddd95960621b6044820152606401610a3b565b333214610d795760405162461bcd60e51b815260206004820152601a60248201527f50726f787920636f6e7472616374206e6f7420616c6c6f7765640000000000006044820152606401610a3b565b60026000541415610d9c5760405162461bcd60e51b8152600401610a3b90613772565b600260005580610de45760405162461bcd60e51b8152602060048201526013602482015272139bc81d1a58dad95d081cdc1958da599a5959606a1b6044820152606401610a3b565b600754811115610e295760405162461bcd60e51b815260206004820152601060248201526f546f6f206d616e79207469636b65747360801b6044820152606401610a3b565b60016000848152600d602052604090205460ff166003811115610e5c57634e487b7160e01b600052602160045260246000fd5b14610e9f5760405162461bcd60e51b81526020600482015260136024820152722637ba3a32b93c9034b9903737ba1037b832b760691b6044820152606401610a3b565b6000838152600d60205260409020600201544210610ef15760405162461bcd60e51b815260206004820152600f60248201526e2637ba3a32b93c9034b99037bb32b960891b6044820152606401610a3b565b6000838152600d602052604081206004810154600390910154610f15919084612eb6565b600b54909150610f30906001600160a01b0316333084612e26565b6000848152600d60205260408120601a018054839290610f51908490613892565b90915550600090505b82811015611282576000848483818110610f8457634e487b7160e01b600052603260045260246000fd5b9050602002016020810190610f99919061352e565b9050620f42408163ffffffff1610158015610fbd5750621e847f8163ffffffff1611155b610ff95760405162461bcd60e51b815260206004820152600d60248201526c4f7574736964652072616e676560981b6044820152606401610a3b565b600086815260106020526040812090611013600a84613ade565b61101e9060016138aa565b63ffffffff1681526020810191909152604001600090812080549161104283613a9f565b9091555050600086815260106020526040812090611061606484613ade565b61106c90600b6138aa565b63ffffffff1681526020810191909152604001600090812080549161109083613a9f565b90915550506000868152601060205260408120906110b06103e884613ade565b6110bb90606f6138aa565b63ffffffff168152602081019190915260400160009081208054916110df83613a9f565b90915550506000868152601060205260408120906110ff61271084613ade565b61110b906104576138aa565b63ffffffff1681526020810191909152604001600090812080549161112f83613a9f565b9091555050600086815260106020526040812090611150620186a084613ade565b61115c90612b676138aa565b63ffffffff1681526020810191909152604001600090812080549161118083613a9f565b90915550506000868152601060205260408120906111a1620f424084613ade565b6111ae906201b2076138aa565b63ffffffff168152602081019190915260400160009081208054916111d283613a9f565b90915550503360008181526011602090815260408083208a84528252808320600680548254600181018455928652848620909201919091558151808301835263ffffffff808816825281850196875282548652600e9094529184209151825495516001600160a01b0316640100000000026001600160c01b0319909616931692909217939093179092558154919061126983613a9f565b919050555050808061127a90613a9f565b915050610f5a565b50604051828152849033907fd7d247b583de1023852eef87b48f54354dbec771d01bc2cc49e96094efc322b99060200160405180910390a3505060016000555050565b6060808260008167ffffffffffffffff8111156112f257634e487b7160e01b600052604160045260246000fd5b60405190808252806020026020018201604052801561131b578160200160208202803683370190505b50905060008267ffffffffffffffff81111561134757634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015611370578160200160208202803683370190505b50905060005b838110156114d257600e60008989848181106113a257634e487b7160e01b600052603260045260246000fd5b90506020020135815260200190815260200160002060000160009054906101000a900463ffffffff168382815181106113eb57634e487b7160e01b600052603260045260246000fd5b63ffffffff909216602092830291909101909101526000600e818a8a8581811061142557634e487b7160e01b600052603260045260246000fd5b602090810292909201358352508101919091526040016000205464010000000090046001600160a01b0316141561148d57600182828151811061147857634e487b7160e01b600052603260045260246000fd5b911515602092830291909101909101526114c0565b60008282815181106114af57634e487b7160e01b600052603260045260246000fd5b911515602092830291909101909101525b806114ca81613a9f565b915050611376565b509093509150505b9250929050565b6001546001600160a01b0316331461150b5760405162461bcd60e51b8152600401610a3b9061373d565b600554158061154d575060036005546000908152600d602052604090205460ff16600381111561154b57634e487b7160e01b600052602160045260246000fd5b145b6115995760405162461bcd60e51b815260206004820152601860248201527f4c6f7474657279206e6f7420696e20636c61696d61626c6500000000000000006044820152606401610a3b565b806001600160a01b031663b37217a46005546006546040516020016115c8929190918252602082015260400190565b60408051808303601f1901815290829052805160209091012060e083901b6001600160e01b03191682526004820152602401600060405180830381600087803b15801561161457600080fd5b505af1158015611628573d6000803e3d6000fd5b50505050806001600160a01b031663a1c4f55a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561166557600080fd5b505afa158015611679573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061169d919061354a565b50600c80546001600160a01b0319166001600160a01b0383169081179091556040517f383f8cb39dfa7c3fb901a460dd449ea924868f0a92ff03da64740fffa5f1de6290600090a250565b6003546001600160a01b031633146117125760405162461bcd60e51b8152600401610a3b906137a9565b600260005414156117355760405162461bcd60e51b8152600401610a3b90613772565b600260005560016000828152600d602052604090205460ff16600381111561176d57634e487b7160e01b600052602160045260246000fd5b146117ad5760405162461bcd60e51b815260206004820152601060248201526f2637ba3a32b93c903737ba1037b832b760811b6044820152606401610a3b565b6000818152600d602052604090206002015442116118005760405162461bcd60e51b815260206004820152601060248201526f2637ba3a32b93c903737ba1037bb32b960811b6044820152606401610a3b565b6006546000828152600d6020908152604091829020601901839055600c548251918201859052918101929092526001600160a01b03169063b37217a49060600160408051808303601f1901815290829052805160209091012060e083901b6001600160e01b03191682526004820152602401600060405180830381600087803b15801561188c57600080fd5b505af11580156118a0573d6000803e3d6000fd5b5050506000828152600d6020908152604091829020805460ff1916600217905560065491519182528392507f3728e75294796694d59d2ffced9c394279baf7b9ebd2702db43f5f04bac67929910160405180910390a2506001600055565b6003546001600160a01b031633146119285760405162461bcd60e51b8152600401610a3b906137a9565b600554158061196a575060036005546000908152600d602052604090205460ff16600381111561196857634e487b7160e01b600052602160045260246000fd5b145b6119b65760405162461bcd60e51b815260206004820152601960248201527f4e6f742074696d6520746f207374617274206c6f7474657279000000000000006044820152606401610a3b565b61012c6119c34287613a37565b1180156119db57506205472c6119d94287613a37565b105b611a275760405162461bcd60e51b815260206004820152601f60248201527f4c6f7474657279206c656e677468206f757473696465206f662072616e6765006044820152606401610a3b565b6009548410158015611a3b57506008548411155b611a7b5760405162461bcd60e51b81526020600482015260116024820152704f757473696465206f66206c696d69747360781b6044820152606401610a3b565b61012c831015611acd5760405162461bcd60e51b815260206004820152601860248201527f446973636f756e742064697669736f7220746f6f206c6f7700000000000000006044820152606401610a3b565b610bb8811115611b175760405162461bcd60e51b81526020600482015260156024820152740a8e4cac2e6eae4f240cccaca40e8dede40d0d2ced605b1b6044820152606401610a3b565b60a0820135608083013560608401356040850135611b3a60208701358735613892565b611b449190613892565b611b4e9190613892565b611b589190613892565b611b629190613892565b61271014611bb25760405162461bcd60e51b815260206004820152601860248201527f52657761726473206d75737420657175616c20313030303000000000000000006044820152606401610a3b565b60058054906000611bc283613a9f565b9091555050604080516101a0810190915280600181526020014281526020018681526020018581526020018481526020018360068060200260405190810160405280929190826006602002808284376000920182905250928452505060208083018590526040805160c080820183528482528184018590528183018590526060808301869052608080840187905260a080850188905285890194909452845180840186528781528087018890528086018890528083018890528082018890528085018890529188019190915260065490870181905291860191909152600a549085015260e09093018290526005548252600d90522081518154829060ff19166001836003811115611ce357634e487b7160e01b600052602160045260246000fd5b02179055506020820151600182015560408201516002820155606082015160038201556080820151600482015560a0820151611d259060058301906006613154565b5060c0820151600b82015560e0820151611d4590600c8301906006613154565b50610100820151611d5c9060128301906006613154565b5061012082015160188201556101408201516019820155610160820151601a82015561018090910151601b909101805463ffffffff191663ffffffff909216919091179055600554600654600a5460408051428152602081018a9052908101889052606081019290925260808201527f367e70f8c0e0c0a6504d92172bda155c02022d532fc85b5d66a9c49e31c8bc779060a00160405180910390a250506000600a55505050565b6003546001600160a01b03163314611e2e5760405162461bcd60e51b8152600401610a3b906137a9565b60026000541415611e515760405162461bcd60e51b8152600401610a3b90613772565b60026000818155838152600d602052604090205460ff166003811115611e8757634e487b7160e01b600052602160045260246000fd5b14611ec85760405162461bcd60e51b81526020600482015260116024820152704c6f7474657279206e6f7420636c6f736560781b6044820152606401610a3b565b600c60009054906101000a90046001600160a01b03166001600160a01b031663fbe5d9176040518163ffffffff1660e01b815260040160206040518083038186803b158015611f1657600080fd5b505afa158015611f2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f4e9190613355565b8214611f905760405162461bcd60e51b8152602060048201526011602482015270273ab6b132b939903737ba10323930bbb760791b6044820152606401610a3b565b600c54604080516350e27aad60e11b815290516000926001600160a01b03169163a1c4f55a916004808301926020929190829003018186803b158015611fd557600080fd5b505afa158015611fe9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061200d919061354a565b6000848152600d60205260408120600b0154919250908190612710906120339082613a37565b6000878152600d60205260409020601a015461204f9190613a18565b61205991906138d2565b90506000805b60068163ffffffff16101561232757600061207b826005613a4e565b9050600061208a8260016138aa565b61209590600a61392d565b61209f9088613ade565b63ffffffff8084166000908152600f60205260409020546120c19291166138aa565b60008a815260106020908152604080832063ffffffff851684529091529020549091506120ef908790613a37565b60008a8152600d6020526040902060120163ffffffff84166006811061212557634e487b7160e01b600052603260045260246000fd5b0155600089815260106020908152604080832063ffffffff85168452909152902054612152908790613a37565b1561227b576000898152600d6020526040902060050163ffffffff83166006811061218d57634e487b7160e01b600052603260045260246000fd5b01541561227657600089815260106020908152604080832063ffffffff85168452909152902054612710906121c3908890613a37565b60008b8152600d60205260409020879060050163ffffffff8616600681106121fb57634e487b7160e01b600052603260045260246000fd5b01546122079190613a18565b61221191906138d2565b61221b91906138d2565b60008a8152600d60205260409020600c0163ffffffff84166006811061225157634e487b7160e01b600052603260045260246000fd5b0155600089815260106020908152604080832063ffffffff8516845290915290205495505b612312565b6000898152600d60205260408120600c0163ffffffff8416600681106122b157634e487b7160e01b600052603260045260246000fd5b01556000898152600d6020526040902061271090869060050163ffffffff8516600681106122ef57634e487b7160e01b600052603260045260246000fd5b01546122fb9190613a18565b61230591906138d2565b61230f9085613892565b93505b5050808061231f90613aba565b91505061205f565b506000868152600d60205260409020601b8101805463ffffffff871663ffffffff19909116179055805460ff19166003179055841561236657600a5560005b6000868152600d60205260409020601a0154612383908390613a37565b61238d9082613892565b600454600b549192506123ad916001600160a01b03908116911683612dbe565b6005546040805163ffffffff87168152602081018690527f98e31a6607b8b15b4d5b91de54f4c09ffe4c4cf162aa532c70b5213754e2e703910160405180910390a25050600160005550505050565b600061012c8410156124505760405162461bcd60e51b815260206004820152601f60248201527f4d757374206265203e3d204d494e5f444953434f554e545f44495649534f52006044820152606401610a3b565b8161249d5760405162461bcd60e51b815260206004820152601d60248201527f4e756d626572206f66207469636b657473206d757374206265203e20300000006044820152606401610a3b565b610a07848484612eb6565b333b156124ee5760405162461bcd60e51b815260206004820152601460248201527310dbdb9d1c9858dd081b9bdd08185b1b1bddd95960621b6044820152606401610a3b565b33321461253d5760405162461bcd60e51b815260206004820152601a60248201527f50726f787920636f6e7472616374206e6f7420616c6c6f7765640000000000006044820152606401610a3b565b600260005414156125605760405162461bcd60e51b8152600401610a3b90613772565b60026000558281146125a65760405162461bcd60e51b815260206004820152600f60248201526e09cdee840e6c2daca40d8cadccee8d608b1b6044820152606401610a3b565b826125e75760405162461bcd60e51b815260206004820152601160248201527004c656e677468206d757374206265203e3607c1b6044820152606401610a3b565b60075483111561262c5760405162461bcd60e51b815260206004820152601060248201526f546f6f206d616e79207469636b65747360801b6044820152606401610a3b565b60036000868152600d602052604090205460ff16600381111561265f57634e487b7160e01b600052602160045260246000fd5b146126a45760405162461bcd60e51b81526020600482015260156024820152744c6f7474657279206e6f7420636c61696d61626c6560581b6044820152606401610a3b565b6000805b84811015612a035760068484838181106126d257634e487b7160e01b600052603260045260246000fd5b90506020020160208101906126e7919061352e565b63ffffffff16106127315760405162461bcd60e51b8152602060048201526014602482015273427261636b6574206f7574206f662072616e676560601b6044820152606401610a3b565b600086868381811061275357634e487b7160e01b600052603260045260246000fd5b90506020020135905080600d60008a815260200190815260200160002060190154116127b55760405162461bcd60e51b81526020600482015260116024820152700a8d2c6d6cae892c840e8dede40d0d2ced607b1b6044820152606401610a3b565b6000888152600d60205260409020601801548110156128095760405162461bcd60e51b815260206004820152601060248201526f5469636b6574496420746f6f206c6f7760801b6044820152606401610a3b565b6000818152600e602052604090205464010000000090046001600160a01b031633146128675760405162461bcd60e51b815260206004820152600d60248201526c2737ba103a34329037bbb732b960991b6044820152606401610a3b565b6000818152600e602052604081208054640100000000600160c01b03191690556128c689838888878181106128ac57634e487b7160e01b600052603260045260246000fd5b90506020020160208101906128c1919061352e565b612ca5565b9050806129155760405162461bcd60e51b815260206004820152601960248201527f4e6f207072697a6520666f72207468697320627261636b6574000000000000006044820152606401610a3b565b85858481811061293557634e487b7160e01b600052603260045260246000fd5b905060200201602081019061294a919061352e565b63ffffffff166005146129e25761299c898388888781811061297c57634e487b7160e01b600052603260045260246000fd5b9050602002016020810190612991919061352e565b6128c19060016138aa565b156129e25760405162461bcd60e51b8152602060048201526016602482015275213930b1b5b2ba1036bab9ba103132903434b3b432b960511b6044820152606401610a3b565b6129ec8185613892565b9350505080806129fb90613a9f565b9150506126a8565b50600b54612a1b906001600160a01b03163383612dbe565b6040805182815260208101869052879133917f0f5fca62da8fb5d95525b49e5eaa7b20bc6bd9e2f6b64b493442d1c0bd6ef486910160405180910390a35050600160005550505050565b6001546001600160a01b03163314612a8f5760405162461bcd60e51b8152600401610a3b9061373d565b6001600160a01b038316612ab55760405162461bcd60e51b8152600401610a3b9061370d565b6001600160a01b038216612adb5760405162461bcd60e51b8152600401610a3b9061370d565b6001600160a01b038116612b015760405162461bcd60e51b8152600401610a3b9061370d565b600380546001600160a01b038581166001600160a01b0319928316811790935560048054868316908416811790915560028054928616929093168217909255604080519384526020840192909252908201527f3e945b7660001d46cfd5e729545f7f0b6c65bdee54066a91c7acad703f1b731e9060600160405180910390a1505050565b6001546001600160a01b03163314612baf5760405162461bcd60e51b8152600401610a3b9061373d565b80821115612bff5760405162461bcd60e51b815260206004820152601b60248201527f6d696e5072696365206d757374206265203c206d6178507269636500000000006044820152606401610a3b565b600991909155600855565b6001546001600160a01b03163314612c345760405162461bcd60e51b8152600401610a3b9061373d565b6001600160a01b038116612c995760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610a3b565b612ca281612e64565b50565b6000838152600d60209081526040808320601b0154858452600e90925282205463ffffffff918216911682612cdb8560016138aa565b612ce690600a61392d565b612cf09084613ade565b63ffffffff8087166000908152600f6020526040902054612d129291166138aa565b90506000612d218660016138aa565b612d2c90600a61392d565b612d369084613ade565b63ffffffff8088166000908152600f6020526040902054612d589291166138aa565b90508063ffffffff168263ffffffff161415612db1576000888152600d60205260409020600c0163ffffffff871660068110612da457634e487b7160e01b600052603260045260246000fd5b0154945050505050610a0a565b6000945050505050610a0a565b6040516001600160a01b038316602482015260448101829052612e2190849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612eed565b505050565b6040516001600160a01b0380851660248301528316604482015260648101829052612e5e9085906323b872dd60e01b90608401612dea565b50505050565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60008382612ec5826001613892565b612ecf9190613a37565b612ed98486613a18565b612ee39190613a18565b610a0791906138d2565b6000612f42826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612fbf9092919063ffffffff16565b805190915015612e215780806020019051810190612f609190613321565b612e215760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610a3b565b6060610a078484600085856001600160a01b0385163b6130215760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a3b565b600080866001600160a01b0316858760405161303d919061361c565b60006040518083038185875af1925050503d806000811461307a576040519150601f19603f3d011682016040523d82523d6000602084013e61307f565b606091505b509150915061308f82828661309a565b979650505050505050565b606083156130a9575081610a0a565b8251156130b95782518084602001fd5b8160405162461bcd60e51b8152600401610a3b91906136da565b604080516101a0810190915280600081526020016000815260200160008152602001600081526020016000815260200161310b613192565b81526020016000815260200161311f613192565b815260200161312c613192565b8152602001600081526020016000815260200160008152602001600063ffffffff1681525090565b8260068101928215613182579160200282015b82811115613182578251825591602001919060010190613167565b5061318e9291506131b0565b5090565b6040518060c001604052806006906020820280368337509192915050565b5b8082111561318e57600081556001016131b1565b80356001600160a01b03811681146131dc57600080fd5b919050565b60008083601f8401126131f2578182fd5b50813567ffffffffffffffff811115613209578182fd5b6020830191508360208260051b85010111156114da57600080fd5b600060208284031215613235578081fd5b610a0a826131c5565b600080600060608486031215613252578182fd5b61325b846131c5565b9250613269602085016131c5565b9150613277604085016131c5565b90509250925092565b60008060408385031215613292578182fd5b61329b836131c5565b946020939093013593505050565b600080600080608085870312156132be578081fd5b6132c7856131c5565b966020860135965060408601359560600135945092505050565b600080602083850312156132f3578182fd5b823567ffffffffffffffff811115613309578283fd5b613315858286016131e1565b90969095509350505050565b600060208284031215613332578081fd5b8151610a0a81613b2d565b60006020828403121561334e578081fd5b5035919050565b600060208284031215613366578081fd5b5051919050565b600080600080600060608688031215613384578081fd5b85359450602086013567ffffffffffffffff808211156133a2578283fd5b6133ae89838a016131e1565b909650945060408801359150808211156133c6578283fd5b506133d3888289016131e1565b969995985093965092949392505050565b6000806000604084860312156133f8578283fd5b83359250602084013567ffffffffffffffff811115613415578283fd5b613421868287016131e1565b9497909650939450505050565b60008060408385031215613440578182fd5b82359150602083013561345281613b2d565b809150509250929050565b6000806040838503121561346f578182fd5b50508035926020909101359150565b600080600060608486031215613492578283fd5b505081359360208301359350604090920135919050565b600080600080600061014086880312156134c1578283fd5b8535945060208601359350604086013592506101208601878111156134e4578182fd5b94979396509194606001933592915050565b60008060006060848603121561350a578081fd5b8335925060208401359150604084013561352381613b3b565b809150509250925092565b60006020828403121561353f578081fd5b8135610a0a81613b3b565b60006020828403121561355b578081fd5b8151610a0a81613b3b565b6000815180845260208085019450808401835b83811015613597578151151587529582019590820190600101613579565b509495945050505050565b8060005b6006811015612e5e5781518452602093840193909101906001016135a6565b6000815180845260208085019450808401835b8381101561359757815163ffffffff16875295820195908201906001016135d8565b6004811061361857634e487b7160e01b600052602160045260246000fd5b9052565b6000825161362e818460208701613a73565b9190910192915050565b6080808252855190820181905260009060209060a0840190828901845b8281101561367157815184529284019290840190600101613655565b5050508381038285015261368581886135c5565b915050828103604084015261369a8186613566565b91505082606083015295945050505050565b6040815260006136bf60408301856135c5565b82810360208401526136d18185613566565b95945050505050565b60208152600082518060208401526136f9816040850160208701613a73565b601f01601f19169190910160400192915050565b60208082526016908201527543616e6e6f74206265207a65726f206164647265737360501b604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b6020808252600c908201526b2737ba1037b832b930ba37b960a11b604082015260600190565b6000610380820190506137e38284516135fa565b6020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015161381d60a08401826135a2565b5060c0830151610160818185015260e08501519150610180613841818601846135a2565b61010086015192506138576102408601846135a2565b6101208601516103008601526101408601516103208601529085015161034085015284015163ffffffff811661036085015290505092915050565b600082198211156138a5576138a5613b01565b500190565b600063ffffffff8083168185168083038211156138c9576138c9613b01565b01949350505050565b6000826138e1576138e1613b17565b500490565b60018163ffffffff825b808611156139245782820483111561390a5761390a613b01565b8086161561391757928202925b94851c94918002916138f0565b50509250929050565b600063ffffffff61394281851682851661394a565b949350505050565b60008261395957506001613a12565b8161396657506000613a12565b816001811461397c5760028114613986576139b7565b6001915050613a12565b60ff84111561399757613997613b01565b6001841b915063ffffffff8211156139b1576139b1613b01565b50613a12565b5060208310610133831016604e8410600b84101617156139ee575081810a63ffffffff8111156139e9576139e9613b01565b613a12565b6139f883836138e6565b8063ffffffff04821115613a0e57613a0e613b01565b0290505b92915050565b6000816000190483118215151615613a3257613a32613b01565b500290565b600082821015613a4957613a49613b01565b500390565b600063ffffffff83811690831681811015613a6b57613a6b613b01565b039392505050565b60005b83811015613a8e578181015183820152602001613a76565b83811115612e5e5750506000910152565b6000600019821415613ab357613ab3613b01565b5060010190565b600063ffffffff80831681811415613ad457613ad4613b01565b6001019392505050565b600063ffffffff80841680613af557613af5613b17565b92169190910692915050565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b8015158114612ca257600080fd5b63ffffffff81168114612ca257600080fdfea264697066735822122077547adc4a7b4b359af97cf47079df381c8fbf53fb716eb838dd4f55b74530b664736f6c63430008040033000000000000000000000000dc4d748e2e368ccc3b0343e2ada95e47dd477cd100000000000000000000000023c9ca246b324c1491d01e9f30c5b6ce88e48335

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

000000000000000000000000dc4d748e2e368ccc3b0343e2ada95e47dd477cd100000000000000000000000023c9ca246b324c1491d01e9f30c5b6ce88e48335

-----Decoded View---------------
Arg [0] : _cakeTokenAddress (address): 0xdc4d748e2e368ccc3b0343e2ada95e47dd477cd1
Arg [1] : _randomGeneratorAddress (address): 0x23c9ca246b324c1491d01e9f30c5b6ce88e48335

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000dc4d748e2e368ccc3b0343e2ada95e47dd477cd1
Arg [1] : 00000000000000000000000023c9ca246b324c1491d01e9f30c5b6ce88e48335


Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Block Uncle Number Difficulty Gas Used Reward
Loading