ETH Price: $2,129.35 (+3.07%)
Gas: 0.14 Gwei

Transaction Decoder

Block:
9977203 at May-01-2020 12:57:24 AM +UTC
Transaction Fee:
0.00047115 ETH $1.00
Gas Used:
47,115 Gas / 10 Gwei

Emitted Events:

19 Lottery.Reveal( roundId=154, user=0x00000000...000000000 )

Account State Difference:

  Address   Before After State Difference Code
(Spark Pool)
99.461094169655913255 Eth99.461565319655913255 Eth0.00047115
0x8c53CDBe...CFf3c113d
0xC105bc4d...3Be42D2b5
19.869892842055670527 Eth
Nonce: 468
19.869421692055670527 Eth
Nonce: 469
0.00047115

Execution Trace

Lottery.reveal( secret=56523413372348391407552613998524567157687979785224754065282943879273033582991 )
{"Adminable.sol":{"content":"pragma solidity ^0.5.2;\n\nimport \"./Ownable.sol\";\n\ncontract Adminable is Ownable {\n    mapping (address =\u003e bool) public admins;\n\n    modifier onlyAdmin() {\n        require(isAdmin(msg.sender), \"not admin\");\n        _;\n    }\n\n    function setAdmin(address user, bool value) external onlyOwner {\n        admins[user] = value;\n    }\n\n    function isAdmin(address user) internal view returns (bool) {\n      return admins[user] || isOwner();\n    }\n}\n"},"Lottery.sol":{"content":"pragma solidity ^0.5.2;\n\nimport \"./Adminable.sol\";\n\ninterface ILottoshi {\n    function contribute(address referral) external payable;\n    function decentralize() external;\n}\n\ncontract Lottery is Adminable {\n    struct Round {\n        uint256 seed;\n        uint256 perWinnerPrizes1;\n        uint256 perWinnerPrizes2;\n        uint256 prizes;\n        uint128 ticketCount;\n        uint128 checkedCount;\n        uint56 result;\n        bool revealed;\n        mapping (address =\u003e bytes32) commitments;\n        mapping (uint256 =\u003e Ticket) tickets;\n        mapping (uint256 =\u003e ComboTicket) comboTickets;\n    }\n\n    struct Ticket {\n        bool claimed;\n        address payable owner;\n        uint56 number;\n    }\n\n    struct ComboTicket {\n        uint256 number1; // zone1Count,zone2Count,zone2Number,zone1Numbers\n        uint256 number2;\n    }\n\n    struct Number {\n        uint256 n0;\n        uint256 n1;\n        uint256 n2;\n        uint256 n3;\n        uint256 n4;\n        uint256 n5;\n        uint256 n6;\n    }\n\n    // production\n    uint256 internal constant NORMAL_DURATION = 24 hours;\n    uint256 internal constant REVEALING_DURATION = 50 minutes;\n    uint256 internal constant CONFIRMING_DURATION = 10 minutes;\n    uint256 internal constant OWNER_TIMEOUT = 10 days;\n\n    uint256 internal constant COST_PER_TICKET = 0.01 ether;\n    uint256 internal constant REVEAL_PRIZE = 0.5 ether;\n    uint256 internal constant PERCENTAGE_TO_FUND = 3000;\n    uint256 internal constant OFFSET = 10000;\n    uint256 internal constant PERCENTAGE_OF_PRIZE1 = 5340; // 53.4%\n    uint256 internal constant PERCENTAGE_OF_PRIZE2 = 660;  // 6.6%\n    uint256[8] internal PRIZES = [\n        COST_PER_TICKET * 1500,\n        COST_PER_TICKET * 200,\n        COST_PER_TICKET * 40,\n        COST_PER_TICKET * 8,\n        COST_PER_TICKET * 4,\n        COST_PER_TICKET * 2,\n        COST_PER_TICKET * 1,\n        COST_PER_TICKET * 1\n    ];\n\n    mapping (uint256 =\u003e Round) public rounds;\n    uint256 public roundId = 1;\n    uint256 public lastAvailablePrize;\n    uint256 public pendingPrize;\n    uint256 public revealingUntil;\n    uint256 public normalUntil;\n    address payable public lottoshi;\n    Status public status = Status.normal;\n    bool public decentralized;\n\n    event Buy(address indexed user, uint256 roundId, uint256 ticketId, address referral, uint56 number, uint256 number1, uint256 number2);\n    event Result(uint256 roundId, uint256 result, uint256 perWinnerPrizes1, uint256 perWinnerPrizes2, uint256 prizes, uint128 ticketCount);\n    event ClaimReward(uint256 roundId, uint256 ticketId);\n    event Commit(uint256 roundId, address user);\n    event Reveal(uint256 roundId, address user);\n    event RevealPrize(uint256 roundId, address user);\n\n    enum Status {\n        normal,\n        revealing,\n        checking\n    }\n\n    constructor() public {\n        normalUntil = uint32(getTime() + NORMAL_DURATION);\n    }\n\n    function() external payable {\n    }\n\n    function setLottoshiAddress(address payable addr) external onlyOwner {\n        require(lottoshi == address(0), \"already set\");\n        lottoshi = addr;\n    }\n\n    function backToNormal() external payable onlyAdmin {\n        require(!decentralized, \"method disabled\");\n        require(status == Status.revealing, \"invalid status\");\n        uint256 cost = REVEAL_PRIZE * 100;\n        require(msg.value \u003e= cost, \"insufficient money\");\n        status = Status.normal;\n        --roundId;\n        normalUntil = uint32(getTime() + NORMAL_DURATION);\n        uint256 tmpRoundId = roundId;\n        if (rounds[tmpRoundId].revealed) {\n            rounds[tmpRoundId].revealed = false;\n        }\n        if (msg.value \u003e cost) {\n            msg.sender.transfer(msg.value - cost);\n        }\n    }\n\n    function buyTickets(uint256[] calldata numbers, address referral) external payable {\n        uint256 length = numbers.length;\n        uint256 totalCost = length * COST_PER_TICKET;\n        require(msg.value \u003e= totalCost, \"insufficient money\");\n\n        address ref = referral == msg.sender ? address(0) : referral;\n        uint256 tmpRoundId = roundId;\n        uint128 ticketCount = rounds[tmpRoundId].ticketCount;\n        for (uint256 i = 0; i \u003c length; i++) {\n            uint256 number = numbers[i];\n            validateNumber(number);\n            ++ticketCount;\n            rounds[tmpRoundId].tickets[ticketCount] = Ticket(false, msg.sender, uint56(number));\n            emit Buy(msg.sender, tmpRoundId, ticketCount, ref, uint56(number), 0, 0);\n        }\n        rounds[tmpRoundId].ticketCount = ticketCount;\n\n        ILottoshi(lottoshi).contribute.value(totalCost * PERCENTAGE_TO_FUND / OFFSET)(ref);\n        if (msg.value - totalCost \u003e 0) {\n            msg.sender.transfer(msg.value - totalCost);\n        }\n    }\n\n    function buyComboTicket(uint256 number1, uint256 number2, address referral) external payable {\n        uint256 zone1Count = number1 \u003e\u003e 248;\n        uint256 zone2Count = (number1 \u003e\u003e 240) \u0026 0xff;\n        require(zone1Count \u003e= 6 \u0026\u0026 zone1Count \u003c= 38, \"invalid zone1Count\");\n        require(zone2Count \u003e= 1 \u0026\u0026 zone2Count \u003c= 8, \"invalid zone2Count\");\n        uint256 count = combinations(zone1Count, 6) * zone2Count;\n        uint256 totalCost = count * COST_PER_TICKET;\n        require(msg.value \u003e= totalCost, \"insufficient money\");\n        validateComboTicket(number1, number2, zone1Count, zone2Count);\n\n        address ref = referral == msg.sender ? address(0) : referral;\n        uint256 tmpRoundId = roundId;\n        uint128 ticketCount = rounds[tmpRoundId].ticketCount;\n        ++ticketCount;\n        rounds[tmpRoundId].tickets[ticketCount] = Ticket(false, msg.sender, 0);\n        rounds[tmpRoundId].comboTickets[ticketCount].number1 = number1;\n        if (number2 != 0) {\n            rounds[tmpRoundId].comboTickets[ticketCount].number2 = number2;\n        }\n        emit Buy(msg.sender, tmpRoundId, ticketCount, ref, 0, number1, number2);\n        rounds[tmpRoundId].ticketCount = ticketCount;\n        ILottoshi(lottoshi).contribute.value(totalCost * PERCENTAGE_TO_FUND / OFFSET)(ref);\n        if (msg.value - totalCost \u003e 0) {\n            msg.sender.transfer(msg.value - totalCost);\n        }\n    }\n\n    function validateComboTicket(uint256 number1, uint256 number2, uint256 zone1Count, uint256 zone2Count) pure internal {\n        uint256 n1 = (number1 \u003e\u003e 232) \u0026 0xff;\n        require(n1 \u003e= 1, \"invalid number\");\n        uint256 length = (zone2Count + 2) \u003c\u003c 3;\n        n1 = validateComboNumber(number1, n1, 24, length);\n        require(n1 \u003c= 8, \"invalid number\");\n\n        n1 = (number1 \u003e\u003e (248 - length)) \u0026 0xff;\n        require(n1 \u003e= 1, \"invalid number\");\n        length = (zone1Count \u003e 30 - zone2Count ? 32 : zone1Count + zone2Count + 2) \u003c\u003c 3;\n        n1 = validateComboNumber(number1, n1, (zone2Count + 3) \u003c\u003c 3, length);\n        if (zone1Count \u003e 30 - zone2Count) {\n            length = (zone1Count - 30 + zone2Count) \u003c\u003c 3;\n            n1 = validateComboNumber(number2, n1, (zone2Count + 3) \u003c\u003c 3, length);\n        }\n        require(n1 \u003c= 38, \"invalid number\");\n    }\n\n    function commit(bytes32 commitment) external {\n        if (isAdmin(msg.sender) \u0026\u0026 !decentralized) {\n            require(getTime() \u003e= normalUntil, \"invalid time\");\n            startRevealing();\n            rounds[roundId - 1].commitments[address(0)] = commitment;\n            emit Commit(roundId - 1, address(0));\n        } else {\n            rounds[roundId].commitments[msg.sender] = commitment;\n            emit Commit(roundId, msg.sender);\n        }\n    }\n\n    function endCommit() external {\n        require(getTime() \u003e= (decentralized ? normalUntil : normalUntil + OWNER_TIMEOUT), \"invalid time\");\n        startRevealing();\n        if (!decentralized) {\n            decentralized = true;\n            ILottoshi(lottoshi).decentralize();\n        }\n    }\n\n    function startRevealing() internal {\n        require(status == Status.normal, \"invalid status\");\n        uint256 prize = getAvailablePrize();\n        require(prize \u003e= REVEAL_PRIZE, \"insufficient money\");\n        ++roundId;\n        status = Status.revealing;\n        revealingUntil = getTime() + REVEALING_DURATION;\n        lastAvailablePrize = prize - REVEAL_PRIZE;\n    }\n\n    function reveal(uint256 secret) external {\n        require(status == Status.revealing, \"invalid status\");\n        uint256 tmpRoundId = roundId - 1;\n        if (isAdmin(msg.sender) \u0026\u0026 !decentralized) {\n            require(getTime() \u003e= revealingUntil + CONFIRMING_DURATION, \"invalid time\");\n            require(getHash(secret) == rounds[tmpRoundId].commitments[address(0)], \"invalid secret\");\n            rounds[tmpRoundId].commitments[address(0)] = 0;\n            uint256 seed = rounds[tmpRoundId].seed;\n            seed += uint256(getBlockHash(block.number - 20));\n            seed += secret;\n            startChecking(seed);\n            rounds[tmpRoundId].seed = seed;\n            emit Reveal(tmpRoundId, address(0));\n        } else {\n            require(getTime() \u003c revealingUntil, \"invalid time\");\n            require(getHash(secret) == rounds[tmpRoundId].commitments[msg.sender], \"invalid secret\");\n            rounds[tmpRoundId].commitments[msg.sender] = 0;\n            rounds[tmpRoundId].seed += secret;\n            emit Reveal(tmpRoundId, msg.sender);\n        }\n        if (!rounds[tmpRoundId].revealed) {\n            rounds[tmpRoundId].revealed = true;\n            msg.sender.transfer(REVEAL_PRIZE);\n            emit RevealPrize(tmpRoundId, msg.sender);\n        }\n    }\n\n    function endReveal() external {\n        require(status == Status.revealing, \"invalid status\");\n        uint256 time = decentralized ? revealingUntil + CONFIRMING_DURATION : revealingUntil + CONFIRMING_DURATION + OWNER_TIMEOUT;\n        require(getTime() \u003e= time, \"invalid time\");\n        uint256 seed = rounds[roundId - 1].seed;\n        seed += uint256(getBlockHash(block.number - 20));\n        rounds[roundId - 1].seed = seed;\n        startChecking(seed);\n        if (!decentralized) {\n            decentralized = true;\n            ILottoshi(lottoshi).decentralize();\n        }\n    }\n\n    function startChecking(uint256 seed) internal {\n        status = Status.checking;\n        uint256[6] memory numbers = drawNumbers(seed);\n        uint256 ns = random(seed + 6, 8) + 1;\n        rounds[roundId - 1].result = uint56(\n            (numbers[0] \u003c\u003c 48) | (numbers[1] \u003c\u003c 40) | (numbers[2] \u003c\u003c 32) |\n            (numbers[3] \u003c\u003c 24) | (numbers[4] \u003c\u003c 16) | (numbers[5] \u003c\u003c 8) | ns\n        );\n    }\n\n    function checkTickets(uint256 count) external {\n        require (status == Status.checking, \"invalid status\");\n        uint256 tmpRoundId = roundId - 1;\n        Round memory round = rounds[tmpRoundId];\n        if (round.ticketCount == 0) {\n            status = Status.normal;\n            normalUntil = getTime() + NORMAL_DURATION;\n            emit Result(tmpRoundId, round.result, 0, 0, 0, 0);\n            return;\n        }\n        require (count \u003e 0, \"invalid count\");\n        uint256 end = round.checkedCount + count;\n        if (end \u003e round.ticketCount) {\n            end = round.ticketCount;\n        }\n        uint256[10] memory prizes = decodePrize(round.prizes);\n        Number memory result = decodeNumberAsStruct(round.result);\n        bool prizesChanged = false;\n        for (uint256 i = round.checkedCount + 1; i \u003c= end; ++i) {\n            uint56 number = rounds[tmpRoundId].tickets[i].number;\n            if (number == 0) {\n                uint256[10] memory levels = getComboPrizeLevels(\n                    rounds[tmpRoundId].comboTickets[i].number1, rounds[tmpRoundId].comboTickets[i].number2, result\n                );\n                for (uint256 j = 0; j \u003c 10; ++j) {\n                    uint256 prizeCount = levels[j];\n                    if (prizeCount \u003e 0) {\n                        prizes[j] += prizeCount;\n                        prizesChanged = true;\n                    }\n                }\n            } else {\n                uint256 level = getPrizeLevel(number, result);\n                if (level \u003e 0) {\n                    ++prizes[level - 1];\n                    prizesChanged = true;\n                }\n            }\n        }\n        round.checkedCount = uint128(end);\n        if (prizesChanged) {\n            rounds[tmpRoundId].prizes = encodePrize(prizes);\n        }\n        // all done\n        if (round.checkedCount == round.ticketCount) {\n            updatePrizes(tmpRoundId, round, prizes);\n            status = Status.normal;\n            normalUntil = uint32(getTime() + NORMAL_DURATION);\n            emit Result(tmpRoundId, round.result, round.perWinnerPrizes1, round.perWinnerPrizes2, rounds[tmpRoundId].prizes, round.ticketCount);\n        }\n        rounds[tmpRoundId].checkedCount = round.checkedCount;\n    }\n\n    function updatePrizes(uint256 tmpRoundId, Round memory round, uint256[10] memory prizes) internal {\n        uint256 fixedPrize;\n        for (uint256 i = 0; i \u003c 8; ++i) {\n            fixedPrize += prizes[i + 2] * PRIZES[i];\n        }\n        require(getAvailablePrize() \u003e= fixedPrize, \"insufficient money\");\n        uint256 remainPrize = lastAvailablePrize;\n        remainPrize = remainPrize \u003e= fixedPrize ? remainPrize - fixedPrize : 0;\n        uint256 prize1 = remainPrize * PERCENTAGE_OF_PRIZE1 / OFFSET;\n        uint256 prize2 = remainPrize * PERCENTAGE_OF_PRIZE2 / OFFSET;\n        uint256 length1 = prizes[0];\n        uint256 length2 = prizes[1];\n        round.perWinnerPrizes1 = length1 == 0 ? 0 : prize1 / length1;\n        round.perWinnerPrizes2 = length2 == 0 ? 0 : prize2 / length2;\n        uint256 totalPrize = fixedPrize + round.perWinnerPrizes2 * length2 + round.perWinnerPrizes1 * length1;\n        if (totalPrize \u003e 0) {\n            pendingPrize += totalPrize;\n        }\n        if (round.perWinnerPrizes1 \u003e 0) {\n            rounds[tmpRoundId].perWinnerPrizes1 = round.perWinnerPrizes1;\n        }\n        if (round.perWinnerPrizes2 \u003e 0) {\n            rounds[tmpRoundId].perWinnerPrizes2 = round.perWinnerPrizes2;\n        }\n    }\n\n    function claimRewards(uint256[] calldata inputs) external {\n        require(inputs.length % 2 == 0 \u0026\u0026 inputs.length \u003e= 2, \"invalid length\");\n        uint256 tmpRoundId = inputs[0];\n        require(rounds[tmpRoundId].checkedCount == rounds[tmpRoundId].ticketCount, \"invalid status\");\n        uint256 totalPrize;\n        address payable user = rounds[tmpRoundId].tickets[inputs[1]].owner;\n        Number memory result = decodeNumberAsStruct(rounds[tmpRoundId].result);\n        for (uint256 i = 0; i \u003c inputs.length; i += 2) {\n            if (tmpRoundId != inputs[i]) {\n                tmpRoundId = inputs[i];\n                require(rounds[tmpRoundId].checkedCount == rounds[tmpRoundId].ticketCount, \"invalid status\");\n                result = decodeNumberAsStruct(rounds[tmpRoundId].result);\n            }\n            uint256 ticketId = inputs[i + 1];\n            Ticket memory ticket = rounds[tmpRoundId].tickets[ticketId];\n            if (ticket.claimed || ticket.owner == address(0) || user != ticket.owner) {\n                continue;\n            }\n            uint256 prize;\n            if (ticket.number == 0) {\n                uint256[10] memory levels = getComboPrizeLevels(\n                    rounds[tmpRoundId].comboTickets[ticketId].number1, rounds[tmpRoundId].comboTickets[ticketId].number2, result\n                );\n                for (uint256 level = 1; level \u003c= 10; ++level) {\n                    uint256 count = levels[level - 1];\n                    if (count \u003e 0) {\n                        if (level == 1) {\n                            prize += rounds[tmpRoundId].perWinnerPrizes1;\n                        } else if (level == 2) {\n                            prize += rounds[tmpRoundId].perWinnerPrizes2 * count;\n                        } else {\n                            prize += PRIZES[level - 3] * count;\n                        }\n                    }\n                }\n            } else {\n                uint256 level = getPrizeLevel(ticket.number, result);\n                if (level == 1) {\n                    prize = rounds[tmpRoundId].perWinnerPrizes1;\n                } else if (level == 2) {\n                    prize = rounds[tmpRoundId].perWinnerPrizes2;\n                } else if (level \u003e 0) {\n                    prize = PRIZES[level - 3];\n                }\n            }\n            if (prize \u003e 0) {\n                totalPrize += prize;\n                rounds[tmpRoundId].tickets[ticketId].claimed = true;\n                emit ClaimReward(tmpRoundId, ticketId);\n            }\n        }\n        require(totalPrize \u003e 0, \"no prize\");\n        require(pendingPrize \u003e= totalPrize, \"insufficient money\");\n        pendingPrize -= totalPrize;\n        user.transfer(totalPrize);\n    }\n\n    function getCommitment(uint256 _roundId, address user) external view returns (bytes32) {\n        return rounds[_roundId].commitments[user];\n    }\n\n    function getTicket(uint256 _roundId, uint256 ticketId) external view returns (bool, address, uint256, uint256, uint256) {\n        Ticket memory ticket = rounds[_roundId].tickets[ticketId];\n        ComboTicket memory comboTicket = rounds[_roundId].comboTickets[ticketId];\n        return (ticket.claimed, ticket.owner, ticket.number, comboTicket.number1, comboTicket.number2);\n    }\n\n    function getAvailablePrize() public view returns (uint256) {\n        return address(this).balance - pendingPrize;\n    }\n\n    function getSystemStatus() external view returns (uint256, Status, uint256, uint256, uint256, uint128, uint128) {\n        uint256 tmpRoundId = roundId;\n        if (status != Status.normal) {\n            --tmpRoundId;\n        }\n        return (\n            roundId,\n            status,\n            normalUntil,\n            revealingUntil + CONFIRMING_DURATION,\n            now,\n            rounds[tmpRoundId].ticketCount,\n            rounds[tmpRoundId].checkedCount\n        );\n    }\n\n    function getPrizeLevel(uint256 number, Number memory result) internal pure returns (uint256) {\n        uint256 hit = 0;\n        uint256 n0 = result.n0;\n        uint256 n1 = result.n1;\n        uint256 n2 = result.n2;\n        uint256 n3 = result.n3;\n        uint256 n4 = result.n4;\n        uint256 n5 = result.n5;\n        for (uint256 i = 8; i \u003c= 48; i += 8) {\n            uint256 n = (number \u003e\u003e i) \u0026 0xff;\n            if (n \u003c n3) {\n                if (n == n0 || n == n1 || n == n2) {\n                    ++hit;\n                }\n            } else {\n                if (n == n3 || n == n4 || n == n5) {\n                    ++hit;\n                }\n            }\n        }\n        if (hit == 0) {\n            return 0;\n        } else if (number \u0026 0xff == result.n6) {\n            if (hit == 1) {\n                return 10;\n            } else if (hit == 2) {\n                return 8;\n            } else if (hit == 3) {\n                return 7;\n            } else if (hit == 4) {\n                return 5;\n            } else if (hit == 5) {\n                return 3;\n            } else {\n                return 1;\n            }\n        } else {\n            if (hit \u003c 3) {\n                return 0;\n            } else if (hit == 3) {\n                return 9;\n            } else if (hit == 4) {\n                return 6;\n            } else if (hit == 5) {\n                return 4;\n            } else {\n                return 2;\n            }\n        }\n    }\n\n    function getComboPrizeLevels(uint256 number1, uint256 number2, Number memory result) internal pure returns (uint256[10] memory) {\n        uint256[10] memory levels;\n        uint256 zone1Count = number1 \u003e\u003e 248;\n        uint256 zone2Count = (number1 \u003e\u003e 240) \u0026 0xff;\n        uint256 n6 = result.n6;\n        uint256 length = (zone2Count + 2) \u003c\u003c 3;\n        uint256 zone2HitCombinations;\n        for (uint256 i = 16; i \u003c length; i += 8) {\n            uint256 n = (number1 \u003e\u003e (248 - i)) \u0026 0xff;\n            if (n == n6) {\n                zone2HitCombinations = 1;\n                break;\n            }\n        }\n        uint256 zone1Hit = getZone1Hit(zone1Count, zone2Count, number1, number2, result);\n        if (zone1Hit \u003e 0) {\n            uint256 zone2NoHitCombinations = zone2Count - zone2HitCombinations;\n            if (zone2HitCombinations == 1) {\n                levels[9] = zone1Hit * combinations(zone1Count - zone1Hit, 5);\n            }\n\n            if (zone1Hit \u003e 1) {\n                if (zone2HitCombinations == 1) {\n                    levels[7] = combinations(zone1Hit, 2) * combinations(zone1Count - zone1Hit, 4);\n                }\n\n                if (zone1Hit \u003e 2) {\n                    uint256 zone1Combinations = combinations(zone1Hit, 3) * combinations(zone1Count - zone1Hit, 3);\n                    levels[6] = zone1Combinations * zone2HitCombinations;\n                    levels[8] = zone1Combinations * zone2NoHitCombinations;\n\n                    if (zone1Hit \u003e 3) {\n                        zone1Combinations = combinations(zone1Hit, 4) * combinations(zone1Count - zone1Hit, 2);\n                        levels[4] = zone1Combinations * zone2HitCombinations;\n                        levels[5] = zone1Combinations * zone2NoHitCombinations;\n\n                        if (zone1Hit \u003e 4) {\n                            zone1Combinations = combinations(zone1Hit, 5) * combinations(zone1Count - zone1Hit, 1);\n                            levels[2] = zone1Combinations * zone2HitCombinations;\n                            levels[3] = zone1Combinations * zone2NoHitCombinations;\n\n                            if (zone1Hit \u003e 5) {\n                                levels[0] = zone2HitCombinations;\n                                levels[1] = zone2NoHitCombinations;\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n        return levels;\n    }\n\n    function getZone1Hit(\n        uint256 zone1Count, uint256 zone2Count, uint256 number1, uint256 number2, Number memory result\n    ) internal pure returns (uint256) {\n        uint256 hit = 0;\n        uint256 n0 = result.n0;\n        uint256 n1 = result.n1;\n        uint256 n2 = result.n2;\n        uint256 n3 = result.n3;\n        uint256 n4 = result.n4;\n        uint256 n5 = result.n5;\n        uint256 length = (zone1Count \u003e 30 - zone2Count ? 32 : zone1Count + zone2Count + 2) \u003c\u003c 3;\n        for (uint256 i = (zone2Count + 2) \u003c\u003c 3; i \u003c length; i += 8) {\n            uint256 n = (number1 \u003e\u003e (248 - i)) \u0026 0xff;\n            if (n \u003c n3) {\n                if (n == n0 || n == n1 || n == n2) {\n                    ++hit;\n                }\n            } else {\n                if (n == n3 || n == n4 || n == n5) {\n                    ++hit;\n                }\n            }\n        }\n        if (zone1Count \u003e 30 - zone2Count) {\n            length = (zone1Count - 30 + zone2Count) * 8;\n            for (uint256 i = 0; i \u003c length; i += 8) {\n                uint256 n = (number2 \u003e\u003e (248 - i)) \u0026 0xff;\n                if (n \u003c n3) {\n                    if (n == n0 || n == n1 || n == n2) {\n                        ++hit;\n                    }\n                } else {\n                    if (n == n3 || n == n4 || n == n5) {\n                        ++hit;\n                    }\n                }\n            }\n        }\n        return hit;\n    }\n\n    function decodeNumberAsStruct(uint256 number) internal pure returns (Number memory) {\n        Number memory numbers;\n        numbers.n6 = number \u0026 0xff;\n        numbers.n5 = (number \u003e\u003e 8) \u0026 0xff;\n        numbers.n4 = (number \u003e\u003e 16) \u0026 0xff;\n        numbers.n3 = (number \u003e\u003e 24) \u0026 0xff;\n        numbers.n2 = (number \u003e\u003e 32) \u0026 0xff;\n        numbers.n1 = (number \u003e\u003e 40) \u0026 0xff;\n        numbers.n0 = (number \u003e\u003e 48) \u0026 0xff;\n        return numbers;\n    }\n\n    function decodePrize(uint256 prize) internal pure returns (uint256[10] memory) {\n        return [\n            (prize \u003e\u003e 240) \u0026 0xffff,\n            (prize \u003e\u003e 224) \u0026 0xffff,\n            (prize \u003e\u003e 208) \u0026 0xffff,\n            (prize \u003e\u003e 192) \u0026 0xffff,\n            (prize \u003e\u003e 160) \u0026 0xffffffff,\n            (prize \u003e\u003e 128) \u0026 0xffffffff,\n            (prize \u003e\u003e 96) \u0026 0xffffffff,\n            (prize \u003e\u003e 64) \u0026 0xffffffff,\n            (prize \u003e\u003e 32) \u0026 0xffffffff,\n            prize \u0026 0xffffffff\n        ];\n    }\n\n    function encodePrize(uint256[10] memory prizes) internal pure returns (uint256) {\n        return (prizes[0] \u003c\u003c 240) | (prizes[1] \u003c\u003c 224) | (prizes[2] \u003c\u003c 208) | (prizes[3] \u003c\u003c 192) | (prizes[4] \u003c\u003c 160) |\n            (prizes[5] \u003c\u003c 128) | (prizes[6] \u003c\u003c 96) | (prizes[7] \u003c\u003c 64) | (prizes[8] \u003c\u003c 32) | prizes[9];\n    }\n\n    function drawNumbers(uint256 seed) internal pure returns (uint256[6] memory) {\n        uint256[6] memory numbers;\n        uint256[38] memory all;\n        for (uint256 i = 0; i \u003c 6; ++i) {\n            uint256 j = random(seed + i, 38 - i) + i;\n            uint256 a = all[i];\n            uint256 b = all[j];\n            all[j] = a == 0 ? i + 1 : a;\n            all[i] = b == 0 ? j + 1 : b;\n        }\n        for (uint256 i = 0; i \u003c 6; ++i) {\n            numbers[i] = all[i];\n        }\n        for (uint256 i = 1; i \u003c 6; ++i) {\n            uint256 n = numbers[i];\n            uint256 j;\n            for (j = i; j \u003e 0 \u0026\u0026 numbers[j - 1] \u003e n; --j) {\n                numbers[j] = numbers[j - 1];\n            }\n            numbers[j] = n;\n        }\n        return numbers;\n    }\n\n    function getHash(uint256 secret) internal pure returns (bytes32) {\n        return keccak256(abi.encode(secret));\n    }\n\n    function random(uint256 seed, uint256 max) internal pure returns (uint256) {\n        return uint256(getHash(seed)) % max;\n    }\n\n    function validateNumber(uint256 number) internal pure {\n        uint256 n0 = (number \u003e\u003e 48) \u0026 0xff;\n        uint256 n1 = (number \u003e\u003e 40) \u0026 0xff;\n        uint256 n2 = (number \u003e\u003e 32) \u0026 0xff;\n        uint256 n3 = (number \u003e\u003e 24) \u0026 0xff;\n        uint256 n4 = (number \u003e\u003e 16) \u0026 0xff;\n        uint256 n5 = (number \u003e\u003e 8) \u0026 0xff;\n        uint256 n6 = number \u0026 0xff;\n        require(n6 \u003e= 1 \u0026\u0026 n6 \u003c= 8, \"invalid number\");\n        require(n5 \u003c= 38, \"invalid number\");\n        require(n5 \u003e n4, \"invalid number\");\n        require(n4 \u003e n3, \"invalid number\");\n        require(n3 \u003e n2, \"invalid number\");\n        require(n2 \u003e n1, \"invalid number\");\n        require(n1 \u003e n0, \"invalid number\");\n        require(n0 \u003e= 1, \"invalid number\");\n    }\n\n    function validateComboNumber(uint256 number, uint256 startN, uint256 start, uint256 end) internal pure returns (uint256) {\n        uint256 n1 = startN;\n        for (uint256 i = start; i \u003c end; i += 8) {\n            uint256 n2 = (number \u003e\u003e (248 - i)) \u0026 0xff;\n            require(n2 \u003e n1, \"invalid number\");\n            n1 = n2;\n        }\n        return n1;\n    }\n\n    function combinations(uint256 n, uint256 m) internal pure returns (uint256) {\n        if (n \u003c m) {\n            return 0;\n        } else if (n == m) {\n            return 1;\n        } else {\n            uint256 r = m \u003c n - m ? m : n - m;\n            if (r == 1) {\n                return n;\n            }\n            uint256 a = n - r + 1;\n            for (uint256 i = a + 1; i \u003c= n; ++i) {\n                a *= i;\n            }\n            uint256 b = 1;\n            for (uint256 i = b + 1; i \u003c= r; ++i) {\n                b *= i;\n            }\n            return a / b;\n        }\n    }\n\n    function getTime() internal view returns (uint256) {\n        return now;\n    }\n\n    function getBlockHash(uint256 number) internal view returns (bytes32) {\n        return blockhash(number);\n    }\n}\n"},"Ownable.sol":{"content":"pragma solidity ^0.5.2;\n\n/*\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with GSN meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\ncontract Context {\n    // Empty internal constructor, to prevent people from mistakenly deploying\n    // an instance of this contract, which should be used via inheritance.\n    constructor () internal { }\n    // solhint-disable-previous-line no-empty-blocks\n\n    function _msgSender() internal view returns (address payable) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view returns (bytes memory) {\n        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691\n        return msg.data;\n    }\n}\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\ncontract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor () internal {\n        address msgSender = _msgSender();\n        _owner = msgSender;\n        emit OwnershipTransferred(address(0), msgSender);\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(isOwner(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Returns true if the caller is the current owner.\n     */\n    function isOwner() public view returns (bool) {\n        return _msgSender() == _owner;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing any functionality that is only available to the owner.\n     */\n    function renounceOwnership() public onlyOwner {\n        emit OwnershipTransferred(_owner, address(0));\n        _owner = address(0);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public onlyOwner {\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     */\n    function _transferOwnership(address newOwner) internal {\n        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n        emit OwnershipTransferred(_owner, newOwner);\n        _owner = newOwner;\n    }\n}"}}