Source Code
Overview
S Balance
S Value
$0.00Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 61079407 | 43 hrs ago | 0.039 S | ||||
| 61079407 | 43 hrs ago | 0.039 S | ||||
| 61026389 | 2 days ago | 0.06064618 S | ||||
| 61026389 | 2 days ago | 0.06064618 S | ||||
| 60955017 | 3 days ago | 0.036 S | ||||
| 60955017 | 3 days ago | 0.036 S | ||||
| 60886463 | 4 days ago | 0.0412561 S | ||||
| 60886463 | 4 days ago | 0.0412561 S | ||||
| 60808298 | 5 days ago | 0.21307467 S | ||||
| 60808298 | 5 days ago | 0.21307467 S | ||||
| 60727501 | 6 days ago | 0.0532549 S | ||||
| 60727501 | 6 days ago | 0.0532549 S | ||||
| 60657198 | 7 days ago | 0.04164705 S | ||||
| 60657198 | 7 days ago | 0.04164705 S | ||||
| 60597351 | 8 days ago | 0.04117647 S | ||||
| 60597351 | 8 days ago | 0.04117647 S | ||||
| 60542551 | 9 days ago | 0.04117647 S | ||||
| 60542551 | 9 days ago | 0.04117647 S | ||||
| 60477163 | 10 days ago | 0.04129954 S | ||||
| 60477163 | 10 days ago | 0.04129954 S | ||||
| 60404486 | 11 days ago | 0.04421386 S | ||||
| 60404486 | 11 days ago | 0.04421386 S | ||||
| 60253256 | 13 days ago | 0.04117647 S | ||||
| 60253256 | 13 days ago | 0.04117647 S | ||||
| 60184489 | 14 days ago | 0.04229727 S |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
LumosLottery
Compiler Version
v0.8.4+commit.c7e474f2
Optimization Enabled:
Yes with 99999 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// 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/ILumosLottery.sol";
/** @title Lumos Lottery.
* @notice It is a contract for a lottery system using
* randomness provided externally.
*/
contract LumosLottery is ReentrancyGuard, ILumosLottery, 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 maxPriceTicketInS = 10 ether;
uint256 public minPriceTicketInS = 0.001 ether;
uint256 public pendingInjectionNextLottery;
uint256 public constant MIN_DISCOUNT_DIVISOR = 300;
uint256 public constant MIN_LENGTH_LOTTERY = 5 minutes; // 5 minutes
uint256 public constant MAX_LENGTH_LOTTERY = 4 days + 5 minutes; // 4 days
uint256 public constant MAX_TREASURY_FEE = 3000; // 30%
IRandomNumberGenerator public randomGenerator;
enum Status {
Pending,
Open,
Close,
Claimable
}
struct Lottery {
Status status;
uint256 startTime;
uint256 endTime;
uint256 priceTicketInS;
uint256 discountDivisor;
uint256[6] rewardsBreakdown; // 0: 1 matching number // 5: 6 matching numbers
uint256 treasuryFee; // 500: 5% // 200: 2% // 50: 0.5%
uint256[6] sPerBracket;
uint256[6] countWinnersPerBracket;
uint256 firstTicketId;
uint256 firstTicketIdNextLottery;
uint256 amountCollectedInS;
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 priceTicketInS,
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);
event TransferS(address indexed from, address indexed to, uint256 value);
/**
* @notice Constructor
* @dev RandomNumberGenerator must be deployed prior to this contract
* @param _randomGeneratorAddress: address of the RandomGenerator contract used to work with Pyth Entropy
*/
constructor(address _randomGeneratorAddress) {
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 payable 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 S to this contract
uint256 amountSToTransfer = _calculateTotalPriceForBulkTickets(
_lotteries[_lotteryId].discountDivisor,
_lotteries[_lotteryId].priceTicketInS,
_ticketNumbers.length
);
// Validate that sent value is at least the required amount
require(msg.value >= amountSToTransfer, "Insufficient S amount");
// Increment the total amount collected for the lottery round
_lotteries[_lotteryId].amountCollectedInS += amountSToTransfer;
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++;
}
// Refund excess amount if user sent more than required
uint256 excessAmount = msg.value - amountSToTransfer;
if (excessAmount > 0) {
_safeTransferS(msg.sender, excessAmount);
}
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 rewardInSToTransfer
uint256 rewardInSToTransfer;
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
rewardInSToTransfer += rewardForTicketId;
}
// Transfer S to msg.sender
_safeTransferS(msg.sender, rewardInSToTransfer);
emit TicketsClaim(msg.sender, rewardInSToTransfer, _lotteryId, _ticketIds.length);
}
/**
* @notice Close lottery
* @param _lotteryId: lottery id
* @dev Callable by operator
*/
function closeLottery(uint256 _lotteryId) external payable 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, forwarding value
randomGenerator.getRandomNumber{value: msg.value}(
uint256(keccak256(abi.encodePacked(_lotteryId, currentTicketId)))
);
_lotteries[_lotteryId].status = Status.Close;
emit LotteryClose(_lotteryId, currentTicketId);
}
/**
* @notice Draw the final number, calculate reward in S 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].amountCollectedInS) * (10000 - _lotteries[_lotteryId].treasuryFee))
) / 10000;
// Initializes the amount to withdraw to treasury
uint256 amountToWithdrawToTreasury;
// Calculate prizes in S 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].sPerBracket[j] =
((_lotteries[_lotteryId].rewardsBreakdown[j] * amountToShareToWinners) /
(_numberTicketsPerLotteryId[_lotteryId][transformedWinningNumber] -
numberAddressesInPreviousBracket)) /
10000;
// Update numberAddressesInPreviousBracket
numberAddressesInPreviousBracket = _numberTicketsPerLotteryId[_lotteryId][transformedWinningNumber];
}
// A. No S to distribute, they are added to the amount to withdraw to treasury address
} else {
_lotteries[_lotteryId].sPerBracket[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].amountCollectedInS - amountToShareToWinners);
// Transfer S to treasury address
_safeTransferS(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 payable 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{value: msg.value}(
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
* @dev Callable by owner or injector address
*/
function injectFunds(uint256 _lotteryId) external payable override onlyOwnerOrInjector {
require(_lotteries[_lotteryId].status == Status.Open, "Lottery not open");
require(msg.value > 0, "Must inject positive amount");
_lotteries[_lotteryId].amountCollectedInS += msg.value;
emit LotteryInjection(_lotteryId, msg.value);
}
/**
* @notice Start the lottery
* @dev Callable by operator
* @param _endTime: endTime of the lottery
* @param _priceTicketInS: price of a ticket in S
* @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 _priceTicketInS,
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((_priceTicketInS >= minPriceTicketInS) && (_priceTicketInS <= maxPriceTicketInS), "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,
priceTicketInS: _priceTicketInS,
discountDivisor: _discountDivisor,
rewardsBreakdown: _rewardsBreakdown,
treasuryFee: _treasuryFee,
sPerBracket: [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,
amountCollectedInS: pendingInjectionNextLottery,
finalNumber: 0
});
emit LotteryOpen(
currentLotteryId,
block.timestamp,
_endTime,
_priceTicketInS,
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 {
IERC20(_tokenAddress).safeTransfer(address(msg.sender), _tokenAmount);
emit AdminTokenRecovery(_tokenAddress, _tokenAmount);
}
/**
* @notice Set S price ticket upper/lower limit
* @dev Only callable by owner
* @param _minPriceTicketInS: minimum price of a ticket in S
* @param _maxPriceTicketInS: maximum price of a ticket in S
*/
function setMinAndMaxTicketPriceInS(uint256 _minPriceTicketInS, uint256 _maxPriceTicketInS) external onlyOwner {
require(_minPriceTicketInS <= _maxPriceTicketInS, "minPrice must be < maxPrice");
minPriceTicketInS = _minPriceTicketInS;
maxPriceTicketInS = _maxPriceTicketInS;
}
/**
* @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 S)
* @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 Calculate cost for buying tickets in a specific lottery
* @param _lotteryId: lottery id
* @param _numberTickets: number of tickets to buy
* @dev Convenient function for frontends to get exact cost
*/
function calculateCostForTickets(uint256 _lotteryId, uint256 _numberTickets) external view returns (uint256) {
require(_lotteries[_lotteryId].status == Status.Open, "Lottery is not open");
require(_numberTickets != 0, "Number of tickets must be > 0");
require(_numberTickets <= maxNumberTicketsPerBuyOrClaim, "Too many tickets");
return
_calculateTotalPriceForBulkTickets(
_lotteries[_lotteryId].discountDivisor,
_lotteries[_lotteryId].priceTicketInS,
_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].sPerBracket[_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;
}
/**
* @notice Transfer native currency (S) safely
* @param to: address to transfer S to
* @param value: S amount to transfer (in wei)
*/
function _safeTransferS(address to, uint256 value) internal {
(bool success, ) = to.call{value: value}("");
require(success, "TransferHelper: S_TRANSFER_FAILED");
emit TransferS(address(this), to, value);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (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 Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
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);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (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() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the 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);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/IERC20Permit.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;
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
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));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
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");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @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");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
/**
* @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).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// 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 cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.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
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [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://consensys.net/diligence/blog/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.8.0/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 functionCallWithValue(target, data, 0, "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");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, 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) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, 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) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or 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 {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// 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
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (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;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0;
interface ILumosLottery {
/**
* @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 payable;
/**
* @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 payable;
/**
* @notice Draw the final number, calculate reward in S 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
* @dev Callable by operator
*/
function injectFunds(uint256 _lotteryId) external payable;
/**
* @notice Start the lottery
* @dev Callable by operator
* @param _endTime: endTime of the lottery
* @param _priceTicketInS: price of a ticket in S
* @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 _priceTicketInS,
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);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
interface IRandomNumberGenerator {
/**
* Requests randomness from a user-provided seed
*/
function getRandomNumber(uint256 _seed) external payable;
/**
* View latest lotteryId numbers
*/
function viewLatestLotteryId() external view returns (uint256);
/**
* Views random result
*/
function viewRandomResult() external view returns (uint32);
}{
"optimizer": {
"enabled": true,
"runs": 99999
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"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":"priceTicketInS","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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"TransferS","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":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lotteryId","type":"uint256"},{"internalType":"uint256","name":"_numberTickets","type":"uint256"}],"name":"calculateCostForTickets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"payable","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":"payable","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"}],"name":"injectFunds","outputs":[],"stateMutability":"payable","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":"maxPriceTicketInS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minPriceTicketInS","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":"_minPriceTicketInS","type":"uint256"},{"internalType":"uint256","name":"_maxPriceTicketInS","type":"uint256"}],"name":"setMinAndMaxTicketPriceInS","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":"_priceTicketInS","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 LumosLottery.Status","name":"status","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"priceTicketInS","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":"sPerBracket","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":"amountCollectedInS","type":"uint256"},{"internalType":"uint32","name":"finalNumber","type":"uint32"}],"internalType":"struct LumosLottery.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"}]Contract Creation Code
60806040526064600755678ac7230489e8000060085566038d7ea4c680006009553480156200002d57600080fd5b50604051620050b2380380620050b28339810160408190526200005091620001ed565b600160005562000060336200019b565b600b80546001600160a01b039092166001600160a01b0319909216919091178155600e6020527fe710864318d4a32f37d6ce54cb3fadbef648dd12d8dbdf53973564d56b7f881c805463ffffffff199081166001179091557fa7c5ba7114a813b50159add3a36832908dc83db71d0b9a24c2ad0f83be958207805482169092179091557f9adb202b1492743bc00c81d33cdc6423fa8c79109027eb6a845391e8fc1f048180548216606f1790557fe0283e559c29e31ee7f56467acc9dd307779c843a883aeeb3bf5c6128c908144805482166104571790557fa1d6913cd9e08c872be3e7525cca82e4fc0fc298a783f19022be725b19be685a80548216612b6717905560056000527fb9bec7e2561f624fe753ff070f1599b306cbf59fafd4e8d5a8184a1ea1841bce80549091166201b2071790556200021d565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600060208284031215620001ff578081fd5b81516001600160a01b038116811462000216578182fd5b9392505050565b614e85806200022d6000396000f3fe6080604052600436106102345760003560e01c80638da5cb5b11610138578063c4937ab9116100b0578063db19da0d1161007f578063e359ebec11610064578063e359ebec14610631578063f2b3c80914610644578063f2fde38b1461065a57600080fd5b8063db19da0d146105ed578063dcbad90d1461060457600080fd5b8063c4937ab914610560578063c5f956af14610580578063c914914f146105ad578063da4ca039146105cd57600080fd5b80639d8ca53111610107578063a785ba60116100ec578063a785ba6014610500578063b1829b8214610520578063c38de5391461054057600080fd5b80639d8ca531146104d7578063a568f0f8146104ea57600080fd5b80638da5cb5b1461043e5780638fc3539a1461046957806398359fa1146104975780639c384653146104aa57600080fd5b80633f138d4b116101cb578063715018a61161019a57806380a061601161017f57806380a061601461040057806385e93cad1461041557806388303dbd1461042b57600080fd5b8063715018a6146103eb5780637cb583bd1461029c57600080fd5b80633f138d4b1461037d578063686465b81461039f5780636b873788146103b55780636be4097c146103d557600080fd5b806312a9769d1161020757806312a9769d146103045780631fe86c6b1461031a5780632423807a146103305780632e530cae1461035d57600080fd5b806302be9daf1461023957806305531eeb1461026c57806307fb5a9c1461029c578063127effb2146102b2575b600080fd5b34801561024557600080fd5b50610259610254366004614785565b61067a565b6040519081526020015b60405180910390f35b34801561027857600080fd5b5061028c6102873660046145d1565b610834565b604051610263949392919061497f565b3480156102a857600080fd5b5061025961012c81565b3480156102be57600080fd5b506003546102df9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610263565b34801561031057600080fd5b50610259600a5481565b34801561032657600080fd5b5061025960075481565b34801561033c57600080fd5b5061035061034b366004614665565b610ce7565b6040516102639190614a72565b34801561036957600080fd5b5061025961037836600461481e565b610e96565b34801561038957600080fd5b5061039d6103983660046145a8565b610f44565b005b3480156103ab57600080fd5b5061025960065481565b3480156103c157600080fd5b5061039d6103d0366004614665565b610fc0565b3480156103e157600080fd5b5061025960055481565b3480156103f757600080fd5b5061039d611034565b34801561040c57600080fd5b50600554610259565b34801561042157600080fd5b5061025960095481565b61039d61043936600461470c565b611048565b34801561044a57600080fd5b5060015473ffffffffffffffffffffffffffffffffffffffff166102df565b34801561047557600080fd5b50610489610484366004614609565b6117d3565b6040516102639291906149f3565b61039d6104a536600461454c565b611aab565b3480156104b657600080fd5b506002546102df9073ffffffffffffffffffffffffffffffffffffffff1681565b61039d6104e5366004614665565b611d39565b3480156104f657600080fd5b5061025960085481565b34801561050c57600080fd5b5061039d61051b366004614785565b612055565b34801561052c57600080fd5b5061039d61053b3660046147d1565b6120d2565b34801561054c57600080fd5b5061039d61055b366004614756565b61274a565b34801561056c57600080fd5b5061025961057b3660046147a6565b612efb565b34801561058c57600080fd5b506004546102df9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156105b957600080fd5b5061039d6105c8366004614695565b612fdb565b3480156105d957600080fd5b5061039d6105e8366004614566565b6137d0565b3480156105f957600080fd5b506102596205472c81565b34801561061057600080fd5b50600b546102df9073ffffffffffffffffffffffffffffffffffffffff1681565b61039d61063f366004614665565b6139f8565b34801561065057600080fd5b50610259610bb881565b34801561066657600080fd5b5061039d61067536600461454c565b613c16565b600060016000848152600c602052604090205460ff1660038111156106c8577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b14610734576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4c6f7474657279206973206e6f74206f70656e0000000000000000000000000060448201526064015b60405180910390fd5b8161079b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f4e756d626572206f66207469636b657473206d757374206265203e2030000000604482015260640161072b565b600754821115610807576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f546f6f206d616e79207469636b65747300000000000000000000000000000000604482015260640161072b565b6000838152600c60205260409020600481015460039091015461082b919084613cca565b90505b92915050565b73ffffffffffffffffffffffffffffffffffffffff84166000908152601060209081526040808320868452909152812054606091829182919085906108798882614ce9565b82111561088d5761088a8882614ce9565b91505b60008267ffffffffffffffff8111156108cf577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040519080825280602002602001820160405280156108f8578160200160208202803683370190505b50905060008367ffffffffffffffff81111561093d577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051908082528060200260200182016040528015610966578160200160208202803683370190505b50905060008467ffffffffffffffff8111156109ab577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040519080825280602002602001820160405280156109d4578160200160208202803683370190505b50905060005b85811015610cc157601060008f73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008e81526020019081526020016000208c82610a3e9190614b35565b81548110610a75577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b9060005260206000200154848281518110610ab9577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001018181525050600d6000858381518110610b02577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6020026020010151815260200190815260200160002060000160009054906101000a900463ffffffff16838281518110610b65577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001019063ffffffff16908163ffffffff1681525050600073ffffffffffffffffffffffffffffffffffffffff16600d6000868481518110610bd4577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602090810291909101810151825281019190915260400160002054640100000000900473ffffffffffffffffffffffffffffffffffffffff161415610c63576001828281518110610c4e577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b91151560209283029190910190910152610caf565b6000828281518110610c9e577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b911515602092830291909101909101525b80610cb981614d51565b9150506109da565b50828282610ccf888f614b35565b98509850985098505050505050945094509450949050565b610cef6143ee565b6000828152600c60205260409081902081516101a081019092528054829060ff166003811115610d48577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6003811115610d80577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b81526001820154602082015260028201546040808301919091526003830154606083015260048301546080830152805160c081019182905260a09092019190600584019060069082845b815481526020019060010190808311610dca575050509183525050600b82015460208201526040805160c081018252910190600c830160068282826020028201915b815481526020019060010190808311610e0c5750505091835250506040805160c081019182905260209092019190601284019060069082845b815481526020019060010190808311610e455750505091835250506018820154602082015260198201546040820152601a8201546060820152601b9091015463ffffffff1660809091015292915050565b600060036000858152600c602052604090205460ff166003811115610ee4577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b14610ef157506000610f3d565b6000848152600c602052604090206019015483118015610f2257506000848152600c60205260409020601801548311155b15610f2f57506000610f3d565b610f3a848484613d01565b90505b9392505050565b610f4c613e34565b610f6d73ffffffffffffffffffffffffffffffffffffffff83163383613eb5565b6040805173ffffffffffffffffffffffffffffffffffffffff84168152602081018390527f74545154aac348a3eac92596bd1971957ca94795f4e954ec5f613b55fab78129910160405180910390a15050565b610fc8613e34565b8061102f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f4d757374206265203e2030000000000000000000000000000000000000000000604482015260640161072b565b600755565b61103c613e34565b6110466000613f42565b565b333b156110b1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f436f6e7472616374206e6f7420616c6c6f776564000000000000000000000000604482015260640161072b565b33321461111a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f50726f787920636f6e7472616374206e6f7420616c6c6f776564000000000000604482015260640161072b565b611122613fb9565b80611189576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4e6f207469636b65742073706563696669656400000000000000000000000000604482015260640161072b565b6007548111156111f5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f546f6f206d616e79207469636b65747300000000000000000000000000000000604482015260640161072b565b60016000848152600c602052604090205460ff166003811115611241577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b146112a8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4c6f7474657279206973206e6f74206f70656e00000000000000000000000000604482015260640161072b565b6000838152600c60205260409020600201544210611322576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f4c6f7474657279206973206f7665720000000000000000000000000000000000604482015260640161072b565b6000838152600c602052604081206004810154600390910154611346919084613cca565b9050803410156113b2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f496e73756666696369656e74205320616d6f756e740000000000000000000000604482015260640161072b565b6000848152600c60205260408120601a0180548392906113d3908490614b35565b90915550600090505b8281101561176c57600084848381811061141f577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b90506020020160208101906114349190614856565b9050620f42408163ffffffff16101580156114585750621e847f8163ffffffff1611155b6114be576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f4f7574736964652072616e676500000000000000000000000000000000000000604482015260640161072b565b6000868152600f60205260408120906114d8600a84614dae565b6114e3906001614b4d565b63ffffffff1681526020810191909152604001600090812080549161150783614d51565b90915550506000868152600f6020526040812090611526606484614dae565b61153190600b614b4d565b63ffffffff1681526020810191909152604001600090812080549161155583614d51565b90915550506000868152600f60205260408120906115756103e884614dae565b61158090606f614b4d565b63ffffffff168152602081019190915260400160009081208054916115a483614d51565b90915550506000868152600f60205260408120906115c461271084614dae565b6115d090610457614b4d565b63ffffffff168152602081019190915260400160009081208054916115f483614d51565b90915550506000868152600f6020526040812090611615620186a084614dae565b61162190612b67614b4d565b63ffffffff1681526020810191909152604001600090812080549161164583614d51565b90915550506000868152600f6020526040812090611666620f424084614dae565b611673906201b207614b4d565b63ffffffff1681526020810191909152604001600090812080549161169783614d51565b90915550503360008181526010602090815260408083208a84528252808320600680548254600181018455928652848620909201919091558151808301835263ffffffff808816825281850196875282548652600d90945291842091518254955173ffffffffffffffffffffffffffffffffffffffff16640100000000027fffffffffffffffff000000000000000000000000000000000000000000000000909616931692909217939093179092558154919061175383614d51565b919050555050808061176490614d51565b9150506113dc565b5060006117798234614ce9565b9050801561178b5761178b338261402d565b604051838152859033907fd7d247b583de1023852eef87b48f54354dbec771d01bc2cc49e96094efc322b99060200160405180910390a350506117ce6001600055565b505050565b6060808260008167ffffffffffffffff811115611819577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051908082528060200260200182016040528015611842578160200160208202803683370190505b50905060008267ffffffffffffffff811115611887577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040519080825280602002602001820160405280156118b0578160200160208202803683370190505b50905060005b83811015611a9c57600d60008989848181106118fb577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b90506020020135815260200190815260200160002060000160009054906101000a900463ffffffff1683828151811061195d577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b63ffffffff909216602092830291909101909101526000600d818a8a858181106119b0577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6020908102929092013583525081019190915260400160002054640100000000900473ffffffffffffffffffffffffffffffffffffffff161415611a3e576001828281518110611a29577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b91151560209283029190910190910152611a8a565b6000828281518110611a79577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b911515602092830291909101909101525b80611a9481614d51565b9150506118b6565b509093509150505b9250929050565b611ab3613e34565b6005541580611b0e575060036005546000908152600c602052604090205460ff166003811115611b0c577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b145b611b74576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4c6f7474657279206e6f7420696e20636c61696d61626c650000000000000000604482015260640161072b565b8073ffffffffffffffffffffffffffffffffffffffff1663b37217a434600554600654604051602001611bb1929190918252602082015260400190565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815290829052805160209091012060e084901b7fffffffff0000000000000000000000000000000000000000000000000000000016825260048201526024016000604051808303818588803b158015611c3257600080fd5b505af1158015611c46573d6000803e3d6000fd5b50505050508073ffffffffffffffffffffffffffffffffffffffff1663a1c4f55a6040518163ffffffff1660e01b815260040160206040518083038186803b158015611c9157600080fd5b505afa158015611ca5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cc99190614872565b50600b80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f383f8cb39dfa7c3fb901a460dd449ea924868f0a92ff03da64740fffa5f1de6290600090a250565b60035473ffffffffffffffffffffffffffffffffffffffff163314611dba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f4e6f74206f70657261746f720000000000000000000000000000000000000000604482015260640161072b565b611dc2613fb9565b60016000828152600c602052604090205460ff166003811115611e0e577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b14611e75576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4c6f7474657279206e6f74206f70656e00000000000000000000000000000000604482015260640161072b565b6000818152600c60205260409020600201544211611eef576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4c6f7474657279206e6f74206f76657200000000000000000000000000000000604482015260640161072b565b6006546000828152600c6020908152604091829020601901839055600b5482519182018590529181019290925273ffffffffffffffffffffffffffffffffffffffff169063b37217a4903490606001604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815290829052805160209091012060e084901b7fffffffff0000000000000000000000000000000000000000000000000000000016825260048201526024016000604051808303818588803b158015611fbf57600080fd5b505af1158015611fd3573d6000803e3d6000fd5b5050506000838152600c602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600217905560065491519182528493507f3728e75294796694d59d2ffced9c394279baf7b9ebd2702db43f5f04bac6792992500160405180910390a26120526001600055565b50565b61205d613e34565b808211156120c7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d696e5072696365206d757374206265203c206d617850726963650000000000604482015260640161072b565b600991909155600855565b60035473ffffffffffffffffffffffffffffffffffffffff163314612153576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f4e6f74206f70657261746f720000000000000000000000000000000000000000604482015260640161072b565b60055415806121ae575060036005546000908152600c602052604090205460ff1660038111156121ac577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b145b612214576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4e6f742074696d6520746f207374617274206c6f747465727900000000000000604482015260640161072b565b61012c6122214287614ce9565b11801561223957506205472c6122374287614ce9565b105b61229f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4c6f7474657279206c656e677468206f757473696465206f662072616e676500604482015260640161072b565b60095484101580156122b357506008548411155b612319576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f4f757473696465206f66206c696d697473000000000000000000000000000000604482015260640161072b565b61012c831015612385576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f446973636f756e742064697669736f7220746f6f206c6f770000000000000000604482015260640161072b565b610bb88111156123f1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f54726561737572792066656520746f6f20686967680000000000000000000000604482015260640161072b565b60a082013560808301356060840135604085013561241460208701358735614b35565b61241e9190614b35565b6124289190614b35565b6124329190614b35565b61243c9190614b35565b612710146124a6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f52657761726473206d75737420657175616c2031303030300000000000000000604482015260640161072b565b600580549060006124b683614d51565b9091555050604080516101a0810190915280600181526020014281526020018681526020018581526020018481526020018360068060200260405190810160405280929190826006602002808284376000920182905250928452505060208083018590526040805160c080820183528482528184018590528183018590526060808301869052608080840187905260a080850188905285890194909452845180840186528781528087018890528086018890528083018890528082018890528085018890529188019190915260065490870181905291860191909152600a549085015260e09093018290526005548252600c9052208151815482907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600183600381111561260e577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b02179055506020820151600182015560408201516002820155606082015160038201556080820151600482015560a0820151612650906005830190600661446f565b5060c0820151600b82015560e082015161267090600c830190600661446f565b50610100820151612687906012830190600661446f565b5061012082015160188201556101408201516019820155610160820151601a82015561018090910151601b90910180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff909216919091179055600554600654600a5460408051428152602081018a9052908101889052606081019290925260808201527f367e70f8c0e0c0a6504d92172bda155c02022d532fc85b5d66a9c49e31c8bc779060a00160405180910390a250506000600a55505050565b60035473ffffffffffffffffffffffffffffffffffffffff1633146127cb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f4e6f74206f70657261746f720000000000000000000000000000000000000000604482015260640161072b565b6127d3613fb9565b60026000838152600c602052604090205460ff16600381111561281f577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b14612886576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f4c6f7474657279206e6f7420636c6f7365000000000000000000000000000000604482015260640161072b565b600b60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663fbe5d9176040518163ffffffff1660e01b815260040160206040518083038186803b1580156128ee57600080fd5b505afa158015612902573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612926919061467d565b821461298e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f4e756d62657273206e6f7420647261776e000000000000000000000000000000604482015260640161072b565b600b54604080517fa1c4f55a000000000000000000000000000000000000000000000000000000008152905160009273ffffffffffffffffffffffffffffffffffffffff169163a1c4f55a916004808301926020929190829003018186803b1580156129f957600080fd5b505afa158015612a0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a319190614872565b6000848152600c60205260408120600b015491925090819061271090612a579082614ce9565b6000878152600c60205260409020601a0154612a739190614cac565b612a7d9190614b75565b90506000805b60068163ffffffff161015612de2576000612a9f826005614d00565b90506000612aae826001614b4d565b612ab990600a614bd0565b612ac39088614dae565b63ffffffff8084166000908152600e6020526040902054612ae5929116614b4d565b60008a8152600f6020908152604080832063ffffffff85168452909152902054909150612b13908790614ce9565b60008a8152600c6020526040902060120163ffffffff841660068110612b62577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b01556000898152600f6020908152604080832063ffffffff85168452909152902054612b8f908790614ce9565b15612d04576000898152600c6020526040902060050163ffffffff831660068110612be3577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b015415612cff576000898152600f6020908152604080832063ffffffff8516845290915290205461271090612c19908890614ce9565b60008b8152600c60205260409020879060050163ffffffff861660068110612c6a577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b0154612c769190614cac565b612c809190614b75565b612c8a9190614b75565b60008a8152600c602081905260409091200163ffffffff841660068110612cda577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b01556000898152600f6020908152604080832063ffffffff8516845290915290205495505b612dcd565b6000898152600c6020819052604082200163ffffffff841660068110612d53577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b01556000898152600c6020526040902061271090869060050163ffffffff851660068110612daa577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b0154612db69190614cac565b612dc09190614b75565b612dca9085614b35565b93505b50508080612dda90614d8a565b915050612a83565b506000868152600c60205260409020601b8101805463ffffffff87167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000090911617905580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660031790558415612e5a57600a5560005b6000868152600c60205260409020601a0154612e77908390614ce9565b612e819082614b35565b600454909150612ea79073ffffffffffffffffffffffffffffffffffffffff168261402d565b6005546040805163ffffffff87168152602081018690527f98e31a6607b8b15b4d5b91de54f4c09ffe4c4cf162aa532c70b5213754e2e703910160405180910390a250505050612ef76001600055565b5050565b600061012c841015612f69576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4d757374206265203e3d204d494e5f444953434f554e545f44495649534f5200604482015260640161072b565b81612fd0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f4e756d626572206f66207469636b657473206d757374206265203e2030000000604482015260640161072b565b610f3a848484613cca565b333b15613044576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f436f6e7472616374206e6f7420616c6c6f776564000000000000000000000000604482015260640161072b565b3332146130ad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f50726f787920636f6e7472616374206e6f7420616c6c6f776564000000000000604482015260640161072b565b6130b5613fb9565b82811461311e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f4e6f742073616d65206c656e6774680000000000000000000000000000000000604482015260640161072b565b82613185576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f4c656e677468206d757374206265203e30000000000000000000000000000000604482015260640161072b565b6007548311156131f1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f546f6f206d616e79207469636b65747300000000000000000000000000000000604482015260640161072b565b60036000868152600c602052604090205460ff16600381111561323d577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b146132a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4c6f7474657279206e6f7420636c61696d61626c650000000000000000000000604482015260640161072b565b6000805b848110156137765760068484838181106132eb577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b90506020020160208101906133009190614856565b63ffffffff161061336d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f427261636b6574206f7574206f662072616e6765000000000000000000000000604482015260640161072b565b60008686838181106133a8577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b90506020020135905080600c60008a81526020019081526020016000206019015411613430576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f5469636b6574496420746f6f2068696768000000000000000000000000000000604482015260640161072b565b6000888152600c60205260409020601801548110156134ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5469636b6574496420746f6f206c6f7700000000000000000000000000000000604482015260640161072b565b6000818152600d6020526040902054640100000000900473ffffffffffffffffffffffffffffffffffffffff163314613540576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f4e6f7420746865206f776e657200000000000000000000000000000000000000604482015260640161072b565b6000818152600d6020526040812080547fffffffffffffffff0000000000000000000000000000000000000000ffffffff1690556135cc89838888878181106135b2577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b90506020020160208101906135c79190614856565b613d01565b905080613635576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4e6f207072697a6520666f72207468697320627261636b657400000000000000604482015260640161072b565b85858481811061366e577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b90506020020160208101906136839190614856565b63ffffffff16600514613755576136ee89838888878181106136ce577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b90506020020160208101906136e39190614856565b6135c7906001614b4d565b15613755576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f427261636b6574206d7573742062652068696768657200000000000000000000604482015260640161072b565b61375f8185614b35565b93505050808061376e90614d51565b9150506132a8565b50613781338261402d565b6040805182815260208101869052879133917f0f5fca62da8fb5d95525b49e5eaa7b20bc6bd9e2f6b64b493442d1c0bd6ef486910160405180910390a3506137c96001600055565b5050505050565b6137d8613e34565b73ffffffffffffffffffffffffffffffffffffffff8316613855576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f43616e6e6f74206265207a65726f206164647265737300000000000000000000604482015260640161072b565b73ffffffffffffffffffffffffffffffffffffffff82166138d2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f43616e6e6f74206265207a65726f206164647265737300000000000000000000604482015260640161072b565b73ffffffffffffffffffffffffffffffffffffffff811661394f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f43616e6e6f74206265207a65726f206164647265737300000000000000000000604482015260640161072b565b6003805473ffffffffffffffffffffffffffffffffffffffff8581167fffffffffffffffffffffffff0000000000000000000000000000000000000000928316811790935560048054868316908416811790915560028054928616929093168217909255604080519384526020840192909252908201527f3e945b7660001d46cfd5e729545f7f0b6c65bdee54066a91c7acad703f1b731e9060600160405180910390a1505050565b60015473ffffffffffffffffffffffffffffffffffffffff16331480613a35575060025473ffffffffffffffffffffffffffffffffffffffff1633145b613a9b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f7220696e6a6563746f720000000000000000000000604482015260640161072b565b60016000828152600c602052604090205460ff166003811115613ae7577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b14613b4e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4c6f7474657279206e6f74206f70656e00000000000000000000000000000000604482015260640161072b565b60003411613bb8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d75737420696e6a65637420706f73697469766520616d6f756e740000000000604482015260640161072b565b6000818152600c60205260408120601a018054349290613bd9908490614b35565b909155505060405134815281907f1bbd659dd628a25f7ff2eabb69c74a56939c539728282275c1c9c1a2d3e340499060200160405180910390a250565b613c1e613e34565b73ffffffffffffffffffffffffffffffffffffffff8116613cc1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161072b565b61205281613f42565b60008382613cd9826001614b35565b613ce39190614ce9565b613ced8486614cac565b613cf79190614cac565b610f3a9190614b75565b6000838152600c60209081526040808320601b0154858452600d90925282205463ffffffff918216911682613d37856001614b4d565b613d4290600a614bd0565b613d4c9084614dae565b63ffffffff8087166000908152600e6020526040902054613d6e929116614b4d565b90506000613d7d866001614b4d565b613d8890600a614bd0565b613d929084614dae565b63ffffffff8088166000908152600e6020526040902054613db4929116614b4d565b90508063ffffffff168263ffffffff161415613e27576000888152600c602081905260409091200163ffffffff871660068110613e1a577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b0154945050505050610f3d565b6000945050505050610f3d565b60015473ffffffffffffffffffffffffffffffffffffffff163314611046576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161072b565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526117ce90849061416f565b6001805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60026000541415614026576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161072b565b6002600055565b60008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114614087576040519150601f19603f3d011682016040523d82523d6000602084013e61408c565b606091505b505090508061411d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f5472616e7366657248656c7065723a20535f5452414e534645525f4641494c4560448201527f4400000000000000000000000000000000000000000000000000000000000000606482015260840161072b565b60405182815273ffffffffffffffffffffffffffffffffffffffff84169030907f3aee93130a536584ec9670aae8663c7be527a75ed5b14099c0e25503627d6b549060200160405180910390a3505050565b60006141d1826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff1661427e9092919063ffffffff16565b90508051600014806141f25750808060200190518101906141f29190614649565b6117ce576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161072b565b6060610f3a8484600085856000808673ffffffffffffffffffffffffffffffffffffffff1685876040516142b29190614963565b60006040518083038185875af1925050503d80600081146142ef576040519150601f19603f3d011682016040523d82523d6000602084013e6142f4565b606091505b509150915061430587838387614312565b925050505b949350505050565b606083156143a557825161439e5773ffffffffffffffffffffffffffffffffffffffff85163b61439e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161072b565b508161430a565b61430a83838151156143ba5781518083602001fd5b806040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161072b9190614a21565b604080516101a081019091528060008152602001600081526020016000815260200160008152602001600081526020016144266144ad565b81526020016000815260200161443a6144ad565b81526020016144476144ad565b8152602001600081526020016000815260200160008152602001600063ffffffff1681525090565b826006810192821561449d579160200282015b8281111561449d578251825591602001919060010190614482565b506144a99291506144cb565b5090565b6040518060c001604052806006906020820280368337509192915050565b5b808211156144a957600081556001016144cc565b803573ffffffffffffffffffffffffffffffffffffffff8116811461450457600080fd5b919050565b60008083601f84011261451a578182fd5b50813567ffffffffffffffff811115614531578182fd5b6020830191508360208260051b8501011115611aa457600080fd5b60006020828403121561455d578081fd5b61082b826144e0565b60008060006060848603121561457a578182fd5b614583846144e0565b9250614591602085016144e0565b915061459f604085016144e0565b90509250925092565b600080604083850312156145ba578182fd5b6145c3836144e0565b946020939093013593505050565b600080600080608085870312156145e6578081fd5b6145ef856144e0565b966020860135965060408601359560600135945092505050565b6000806020838503121561461b578182fd5b823567ffffffffffffffff811115614631578283fd5b61463d85828601614509565b90969095509350505050565b60006020828403121561465a578081fd5b8151610f3d81614e2f565b600060208284031215614676578081fd5b5035919050565b60006020828403121561468e578081fd5b5051919050565b6000806000806000606086880312156146ac578081fd5b85359450602086013567ffffffffffffffff808211156146ca578283fd5b6146d689838a01614509565b909650945060408801359150808211156146ee578283fd5b506146fb88828901614509565b969995985093965092949392505050565b600080600060408486031215614720578283fd5b83359250602084013567ffffffffffffffff81111561473d578283fd5b61474986828701614509565b9497909650939450505050565b60008060408385031215614768578182fd5b82359150602083013561477a81614e2f565b809150509250929050565b60008060408385031215614797578182fd5b50508035926020909101359150565b6000806000606084860312156147ba578283fd5b505081359360208301359350604090920135919050565b600080600080600061014086880312156147e9578283fd5b85359450602086013593506040860135925061012086018781111561480c578182fd5b94979396509194606001933592915050565b600080600060608486031215614832578081fd5b8335925060208401359150604084013561484b81614e3d565b809150509250925092565b600060208284031215614867578081fd5b8135610f3d81614e3d565b600060208284031215614883578081fd5b8151610f3d81614e3d565b6000815180845260208085019450808401835b838110156148bf5781511515875295820195908201906001016148a1565b509495945050505050565b8060005b60068110156148ed5781518452602093840193909101906001016148ce565b50505050565b6000815180845260208085019450808401835b838110156148bf57815163ffffffff1687529582019590820190600101614906565b6004811061495f577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b60008251614975818460208701614d25565b9190910192915050565b6080808252855190820181905260009060209060a0840190828901845b828110156149b85781518452928401929084019060010161499c565b505050838103828501526149cc81886148f3565b91505082810360408401526149e1818661488e565b91505082606083015295945050505050565b604081526000614a0660408301856148f3565b8281036020840152614a18818561488e565b95945050505050565b6020815260008251806020840152614a40816040850160208701614d25565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b600061038082019050614a86828451614928565b6020830151602083015260408301516040830152606083015160608301526080830151608083015260a0830151614ac060a08401826148ca565b5060c0830151610160818185015260e08501519150610180614ae4818601846148ca565b6101008601519250614afa6102408601846148ca565b6101208601516103008601526101408601516103208601529085015161034085015284015163ffffffff811661036085015290505092915050565b60008219821115614b4857614b48614dd1565b500190565b600063ffffffff808316818516808303821115614b6c57614b6c614dd1565b01949350505050565b600082614b8457614b84614e00565b500490565b60018163ffffffff825b80861115614bc757828204831115614bad57614bad614dd1565b80861615614bba57928202925b94851c9491800291614b93565b50509250929050565b600063ffffffff61430a818516828516600082614bef5750600161082e565b81614bfc5750600061082e565b8160018114614c125760028114614c1c57614c4d565b600191505061082e565b60ff841115614c2d57614c2d614dd1565b6001841b915063ffffffff821115614c4757614c47614dd1565b5061082e565b5060208310610133831016604e8410600b8410161715614c84575081810a63ffffffff811115614c7f57614c7f614dd1565b61082e565b614c8e8383614b89565b8063ffffffff04821115614ca457614ca4614dd1565b029392505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615614ce457614ce4614dd1565b500290565b600082821015614cfb57614cfb614dd1565b500390565b600063ffffffff83811690831681811015614d1d57614d1d614dd1565b039392505050565b60005b83811015614d40578181015183820152602001614d28565b838111156148ed5750506000910152565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415614d8357614d83614dd1565b5060010190565b600063ffffffff80831681811415614da457614da4614dd1565b6001019392505050565b600063ffffffff80841680614dc557614dc5614e00565b92169190910692915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b801515811461205257600080fd5b63ffffffff8116811461205257600080fdfea2646970667358221220cff41e03b1bc4bd911a102e6ab2adc67a0dcdb674cb40e64b0b5fd92d96b8b8364736f6c63430008040033000000000000000000000000330a1a59604b838c26e1aaf25dd5dc1c1ddc545a
Deployed Bytecode
0x6080604052600436106102345760003560e01c80638da5cb5b11610138578063c4937ab9116100b0578063db19da0d1161007f578063e359ebec11610064578063e359ebec14610631578063f2b3c80914610644578063f2fde38b1461065a57600080fd5b8063db19da0d146105ed578063dcbad90d1461060457600080fd5b8063c4937ab914610560578063c5f956af14610580578063c914914f146105ad578063da4ca039146105cd57600080fd5b80639d8ca53111610107578063a785ba60116100ec578063a785ba6014610500578063b1829b8214610520578063c38de5391461054057600080fd5b80639d8ca531146104d7578063a568f0f8146104ea57600080fd5b80638da5cb5b1461043e5780638fc3539a1461046957806398359fa1146104975780639c384653146104aa57600080fd5b80633f138d4b116101cb578063715018a61161019a57806380a061601161017f57806380a061601461040057806385e93cad1461041557806388303dbd1461042b57600080fd5b8063715018a6146103eb5780637cb583bd1461029c57600080fd5b80633f138d4b1461037d578063686465b81461039f5780636b873788146103b55780636be4097c146103d557600080fd5b806312a9769d1161020757806312a9769d146103045780631fe86c6b1461031a5780632423807a146103305780632e530cae1461035d57600080fd5b806302be9daf1461023957806305531eeb1461026c57806307fb5a9c1461029c578063127effb2146102b2575b600080fd5b34801561024557600080fd5b50610259610254366004614785565b61067a565b6040519081526020015b60405180910390f35b34801561027857600080fd5b5061028c6102873660046145d1565b610834565b604051610263949392919061497f565b3480156102a857600080fd5b5061025961012c81565b3480156102be57600080fd5b506003546102df9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610263565b34801561031057600080fd5b50610259600a5481565b34801561032657600080fd5b5061025960075481565b34801561033c57600080fd5b5061035061034b366004614665565b610ce7565b6040516102639190614a72565b34801561036957600080fd5b5061025961037836600461481e565b610e96565b34801561038957600080fd5b5061039d6103983660046145a8565b610f44565b005b3480156103ab57600080fd5b5061025960065481565b3480156103c157600080fd5b5061039d6103d0366004614665565b610fc0565b3480156103e157600080fd5b5061025960055481565b3480156103f757600080fd5b5061039d611034565b34801561040c57600080fd5b50600554610259565b34801561042157600080fd5b5061025960095481565b61039d61043936600461470c565b611048565b34801561044a57600080fd5b5060015473ffffffffffffffffffffffffffffffffffffffff166102df565b34801561047557600080fd5b50610489610484366004614609565b6117d3565b6040516102639291906149f3565b61039d6104a536600461454c565b611aab565b3480156104b657600080fd5b506002546102df9073ffffffffffffffffffffffffffffffffffffffff1681565b61039d6104e5366004614665565b611d39565b3480156104f657600080fd5b5061025960085481565b34801561050c57600080fd5b5061039d61051b366004614785565b612055565b34801561052c57600080fd5b5061039d61053b3660046147d1565b6120d2565b34801561054c57600080fd5b5061039d61055b366004614756565b61274a565b34801561056c57600080fd5b5061025961057b3660046147a6565b612efb565b34801561058c57600080fd5b506004546102df9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156105b957600080fd5b5061039d6105c8366004614695565b612fdb565b3480156105d957600080fd5b5061039d6105e8366004614566565b6137d0565b3480156105f957600080fd5b506102596205472c81565b34801561061057600080fd5b50600b546102df9073ffffffffffffffffffffffffffffffffffffffff1681565b61039d61063f366004614665565b6139f8565b34801561065057600080fd5b50610259610bb881565b34801561066657600080fd5b5061039d61067536600461454c565b613c16565b600060016000848152600c602052604090205460ff1660038111156106c8577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b14610734576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4c6f7474657279206973206e6f74206f70656e0000000000000000000000000060448201526064015b60405180910390fd5b8161079b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f4e756d626572206f66207469636b657473206d757374206265203e2030000000604482015260640161072b565b600754821115610807576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f546f6f206d616e79207469636b65747300000000000000000000000000000000604482015260640161072b565b6000838152600c60205260409020600481015460039091015461082b919084613cca565b90505b92915050565b73ffffffffffffffffffffffffffffffffffffffff84166000908152601060209081526040808320868452909152812054606091829182919085906108798882614ce9565b82111561088d5761088a8882614ce9565b91505b60008267ffffffffffffffff8111156108cf577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040519080825280602002602001820160405280156108f8578160200160208202803683370190505b50905060008367ffffffffffffffff81111561093d577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051908082528060200260200182016040528015610966578160200160208202803683370190505b50905060008467ffffffffffffffff8111156109ab577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040519080825280602002602001820160405280156109d4578160200160208202803683370190505b50905060005b85811015610cc157601060008f73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008e81526020019081526020016000208c82610a3e9190614b35565b81548110610a75577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b9060005260206000200154848281518110610ab9577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001018181525050600d6000858381518110610b02577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6020026020010151815260200190815260200160002060000160009054906101000a900463ffffffff16838281518110610b65577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001019063ffffffff16908163ffffffff1681525050600073ffffffffffffffffffffffffffffffffffffffff16600d6000868481518110610bd4577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602090810291909101810151825281019190915260400160002054640100000000900473ffffffffffffffffffffffffffffffffffffffff161415610c63576001828281518110610c4e577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b91151560209283029190910190910152610caf565b6000828281518110610c9e577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b911515602092830291909101909101525b80610cb981614d51565b9150506109da565b50828282610ccf888f614b35565b98509850985098505050505050945094509450949050565b610cef6143ee565b6000828152600c60205260409081902081516101a081019092528054829060ff166003811115610d48577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6003811115610d80577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b81526001820154602082015260028201546040808301919091526003830154606083015260048301546080830152805160c081019182905260a09092019190600584019060069082845b815481526020019060010190808311610dca575050509183525050600b82015460208201526040805160c081018252910190600c830160068282826020028201915b815481526020019060010190808311610e0c5750505091835250506040805160c081019182905260209092019190601284019060069082845b815481526020019060010190808311610e455750505091835250506018820154602082015260198201546040820152601a8201546060820152601b9091015463ffffffff1660809091015292915050565b600060036000858152600c602052604090205460ff166003811115610ee4577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b14610ef157506000610f3d565b6000848152600c602052604090206019015483118015610f2257506000848152600c60205260409020601801548311155b15610f2f57506000610f3d565b610f3a848484613d01565b90505b9392505050565b610f4c613e34565b610f6d73ffffffffffffffffffffffffffffffffffffffff83163383613eb5565b6040805173ffffffffffffffffffffffffffffffffffffffff84168152602081018390527f74545154aac348a3eac92596bd1971957ca94795f4e954ec5f613b55fab78129910160405180910390a15050565b610fc8613e34565b8061102f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f4d757374206265203e2030000000000000000000000000000000000000000000604482015260640161072b565b600755565b61103c613e34565b6110466000613f42565b565b333b156110b1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f436f6e7472616374206e6f7420616c6c6f776564000000000000000000000000604482015260640161072b565b33321461111a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f50726f787920636f6e7472616374206e6f7420616c6c6f776564000000000000604482015260640161072b565b611122613fb9565b80611189576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4e6f207469636b65742073706563696669656400000000000000000000000000604482015260640161072b565b6007548111156111f5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f546f6f206d616e79207469636b65747300000000000000000000000000000000604482015260640161072b565b60016000848152600c602052604090205460ff166003811115611241577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b146112a8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4c6f7474657279206973206e6f74206f70656e00000000000000000000000000604482015260640161072b565b6000838152600c60205260409020600201544210611322576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f4c6f7474657279206973206f7665720000000000000000000000000000000000604482015260640161072b565b6000838152600c602052604081206004810154600390910154611346919084613cca565b9050803410156113b2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f496e73756666696369656e74205320616d6f756e740000000000000000000000604482015260640161072b565b6000848152600c60205260408120601a0180548392906113d3908490614b35565b90915550600090505b8281101561176c57600084848381811061141f577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b90506020020160208101906114349190614856565b9050620f42408163ffffffff16101580156114585750621e847f8163ffffffff1611155b6114be576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f4f7574736964652072616e676500000000000000000000000000000000000000604482015260640161072b565b6000868152600f60205260408120906114d8600a84614dae565b6114e3906001614b4d565b63ffffffff1681526020810191909152604001600090812080549161150783614d51565b90915550506000868152600f6020526040812090611526606484614dae565b61153190600b614b4d565b63ffffffff1681526020810191909152604001600090812080549161155583614d51565b90915550506000868152600f60205260408120906115756103e884614dae565b61158090606f614b4d565b63ffffffff168152602081019190915260400160009081208054916115a483614d51565b90915550506000868152600f60205260408120906115c461271084614dae565b6115d090610457614b4d565b63ffffffff168152602081019190915260400160009081208054916115f483614d51565b90915550506000868152600f6020526040812090611615620186a084614dae565b61162190612b67614b4d565b63ffffffff1681526020810191909152604001600090812080549161164583614d51565b90915550506000868152600f6020526040812090611666620f424084614dae565b611673906201b207614b4d565b63ffffffff1681526020810191909152604001600090812080549161169783614d51565b90915550503360008181526010602090815260408083208a84528252808320600680548254600181018455928652848620909201919091558151808301835263ffffffff808816825281850196875282548652600d90945291842091518254955173ffffffffffffffffffffffffffffffffffffffff16640100000000027fffffffffffffffff000000000000000000000000000000000000000000000000909616931692909217939093179092558154919061175383614d51565b919050555050808061176490614d51565b9150506113dc565b5060006117798234614ce9565b9050801561178b5761178b338261402d565b604051838152859033907fd7d247b583de1023852eef87b48f54354dbec771d01bc2cc49e96094efc322b99060200160405180910390a350506117ce6001600055565b505050565b6060808260008167ffffffffffffffff811115611819577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051908082528060200260200182016040528015611842578160200160208202803683370190505b50905060008267ffffffffffffffff811115611887577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040519080825280602002602001820160405280156118b0578160200160208202803683370190505b50905060005b83811015611a9c57600d60008989848181106118fb577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b90506020020135815260200190815260200160002060000160009054906101000a900463ffffffff1683828151811061195d577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b63ffffffff909216602092830291909101909101526000600d818a8a858181106119b0577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6020908102929092013583525081019190915260400160002054640100000000900473ffffffffffffffffffffffffffffffffffffffff161415611a3e576001828281518110611a29577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b91151560209283029190910190910152611a8a565b6000828281518110611a79577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b911515602092830291909101909101525b80611a9481614d51565b9150506118b6565b509093509150505b9250929050565b611ab3613e34565b6005541580611b0e575060036005546000908152600c602052604090205460ff166003811115611b0c577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b145b611b74576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4c6f7474657279206e6f7420696e20636c61696d61626c650000000000000000604482015260640161072b565b8073ffffffffffffffffffffffffffffffffffffffff1663b37217a434600554600654604051602001611bb1929190918252602082015260400190565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815290829052805160209091012060e084901b7fffffffff0000000000000000000000000000000000000000000000000000000016825260048201526024016000604051808303818588803b158015611c3257600080fd5b505af1158015611c46573d6000803e3d6000fd5b50505050508073ffffffffffffffffffffffffffffffffffffffff1663a1c4f55a6040518163ffffffff1660e01b815260040160206040518083038186803b158015611c9157600080fd5b505afa158015611ca5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cc99190614872565b50600b80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f383f8cb39dfa7c3fb901a460dd449ea924868f0a92ff03da64740fffa5f1de6290600090a250565b60035473ffffffffffffffffffffffffffffffffffffffff163314611dba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f4e6f74206f70657261746f720000000000000000000000000000000000000000604482015260640161072b565b611dc2613fb9565b60016000828152600c602052604090205460ff166003811115611e0e577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b14611e75576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4c6f7474657279206e6f74206f70656e00000000000000000000000000000000604482015260640161072b565b6000818152600c60205260409020600201544211611eef576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4c6f7474657279206e6f74206f76657200000000000000000000000000000000604482015260640161072b565b6006546000828152600c6020908152604091829020601901839055600b5482519182018590529181019290925273ffffffffffffffffffffffffffffffffffffffff169063b37217a4903490606001604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815290829052805160209091012060e084901b7fffffffff0000000000000000000000000000000000000000000000000000000016825260048201526024016000604051808303818588803b158015611fbf57600080fd5b505af1158015611fd3573d6000803e3d6000fd5b5050506000838152600c602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600217905560065491519182528493507f3728e75294796694d59d2ffced9c394279baf7b9ebd2702db43f5f04bac6792992500160405180910390a26120526001600055565b50565b61205d613e34565b808211156120c7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6d696e5072696365206d757374206265203c206d617850726963650000000000604482015260640161072b565b600991909155600855565b60035473ffffffffffffffffffffffffffffffffffffffff163314612153576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f4e6f74206f70657261746f720000000000000000000000000000000000000000604482015260640161072b565b60055415806121ae575060036005546000908152600c602052604090205460ff1660038111156121ac577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b145b612214576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4e6f742074696d6520746f207374617274206c6f747465727900000000000000604482015260640161072b565b61012c6122214287614ce9565b11801561223957506205472c6122374287614ce9565b105b61229f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4c6f7474657279206c656e677468206f757473696465206f662072616e676500604482015260640161072b565b60095484101580156122b357506008548411155b612319576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f4f757473696465206f66206c696d697473000000000000000000000000000000604482015260640161072b565b61012c831015612385576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f446973636f756e742064697669736f7220746f6f206c6f770000000000000000604482015260640161072b565b610bb88111156123f1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f54726561737572792066656520746f6f20686967680000000000000000000000604482015260640161072b565b60a082013560808301356060840135604085013561241460208701358735614b35565b61241e9190614b35565b6124289190614b35565b6124329190614b35565b61243c9190614b35565b612710146124a6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f52657761726473206d75737420657175616c2031303030300000000000000000604482015260640161072b565b600580549060006124b683614d51565b9091555050604080516101a0810190915280600181526020014281526020018681526020018581526020018481526020018360068060200260405190810160405280929190826006602002808284376000920182905250928452505060208083018590526040805160c080820183528482528184018590528183018590526060808301869052608080840187905260a080850188905285890194909452845180840186528781528087018890528086018890528083018890528082018890528085018890529188019190915260065490870181905291860191909152600a549085015260e09093018290526005548252600c9052208151815482907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600183600381111561260e577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b02179055506020820151600182015560408201516002820155606082015160038201556080820151600482015560a0820151612650906005830190600661446f565b5060c0820151600b82015560e082015161267090600c830190600661446f565b50610100820151612687906012830190600661446f565b5061012082015160188201556101408201516019820155610160820151601a82015561018090910151601b90910180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff909216919091179055600554600654600a5460408051428152602081018a9052908101889052606081019290925260808201527f367e70f8c0e0c0a6504d92172bda155c02022d532fc85b5d66a9c49e31c8bc779060a00160405180910390a250506000600a55505050565b60035473ffffffffffffffffffffffffffffffffffffffff1633146127cb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f4e6f74206f70657261746f720000000000000000000000000000000000000000604482015260640161072b565b6127d3613fb9565b60026000838152600c602052604090205460ff16600381111561281f577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b14612886576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f4c6f7474657279206e6f7420636c6f7365000000000000000000000000000000604482015260640161072b565b600b60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663fbe5d9176040518163ffffffff1660e01b815260040160206040518083038186803b1580156128ee57600080fd5b505afa158015612902573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612926919061467d565b821461298e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f4e756d62657273206e6f7420647261776e000000000000000000000000000000604482015260640161072b565b600b54604080517fa1c4f55a000000000000000000000000000000000000000000000000000000008152905160009273ffffffffffffffffffffffffffffffffffffffff169163a1c4f55a916004808301926020929190829003018186803b1580156129f957600080fd5b505afa158015612a0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a319190614872565b6000848152600c60205260408120600b015491925090819061271090612a579082614ce9565b6000878152600c60205260409020601a0154612a739190614cac565b612a7d9190614b75565b90506000805b60068163ffffffff161015612de2576000612a9f826005614d00565b90506000612aae826001614b4d565b612ab990600a614bd0565b612ac39088614dae565b63ffffffff8084166000908152600e6020526040902054612ae5929116614b4d565b60008a8152600f6020908152604080832063ffffffff85168452909152902054909150612b13908790614ce9565b60008a8152600c6020526040902060120163ffffffff841660068110612b62577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b01556000898152600f6020908152604080832063ffffffff85168452909152902054612b8f908790614ce9565b15612d04576000898152600c6020526040902060050163ffffffff831660068110612be3577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b015415612cff576000898152600f6020908152604080832063ffffffff8516845290915290205461271090612c19908890614ce9565b60008b8152600c60205260409020879060050163ffffffff861660068110612c6a577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b0154612c769190614cac565b612c809190614b75565b612c8a9190614b75565b60008a8152600c602081905260409091200163ffffffff841660068110612cda577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b01556000898152600f6020908152604080832063ffffffff8516845290915290205495505b612dcd565b6000898152600c6020819052604082200163ffffffff841660068110612d53577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b01556000898152600c6020526040902061271090869060050163ffffffff851660068110612daa577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b0154612db69190614cac565b612dc09190614b75565b612dca9085614b35565b93505b50508080612dda90614d8a565b915050612a83565b506000868152600c60205260409020601b8101805463ffffffff87167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000090911617905580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660031790558415612e5a57600a5560005b6000868152600c60205260409020601a0154612e77908390614ce9565b612e819082614b35565b600454909150612ea79073ffffffffffffffffffffffffffffffffffffffff168261402d565b6005546040805163ffffffff87168152602081018690527f98e31a6607b8b15b4d5b91de54f4c09ffe4c4cf162aa532c70b5213754e2e703910160405180910390a250505050612ef76001600055565b5050565b600061012c841015612f69576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4d757374206265203e3d204d494e5f444953434f554e545f44495649534f5200604482015260640161072b565b81612fd0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f4e756d626572206f66207469636b657473206d757374206265203e2030000000604482015260640161072b565b610f3a848484613cca565b333b15613044576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f436f6e7472616374206e6f7420616c6c6f776564000000000000000000000000604482015260640161072b565b3332146130ad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f50726f787920636f6e7472616374206e6f7420616c6c6f776564000000000000604482015260640161072b565b6130b5613fb9565b82811461311e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f4e6f742073616d65206c656e6774680000000000000000000000000000000000604482015260640161072b565b82613185576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f4c656e677468206d757374206265203e30000000000000000000000000000000604482015260640161072b565b6007548311156131f1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f546f6f206d616e79207469636b65747300000000000000000000000000000000604482015260640161072b565b60036000868152600c602052604090205460ff16600381111561323d577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b146132a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4c6f7474657279206e6f7420636c61696d61626c650000000000000000000000604482015260640161072b565b6000805b848110156137765760068484838181106132eb577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b90506020020160208101906133009190614856565b63ffffffff161061336d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f427261636b6574206f7574206f662072616e6765000000000000000000000000604482015260640161072b565b60008686838181106133a8577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b90506020020135905080600c60008a81526020019081526020016000206019015411613430576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f5469636b6574496420746f6f2068696768000000000000000000000000000000604482015260640161072b565b6000888152600c60205260409020601801548110156134ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5469636b6574496420746f6f206c6f7700000000000000000000000000000000604482015260640161072b565b6000818152600d6020526040902054640100000000900473ffffffffffffffffffffffffffffffffffffffff163314613540576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f4e6f7420746865206f776e657200000000000000000000000000000000000000604482015260640161072b565b6000818152600d6020526040812080547fffffffffffffffff0000000000000000000000000000000000000000ffffffff1690556135cc89838888878181106135b2577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b90506020020160208101906135c79190614856565b613d01565b905080613635576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4e6f207072697a6520666f72207468697320627261636b657400000000000000604482015260640161072b565b85858481811061366e577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b90506020020160208101906136839190614856565b63ffffffff16600514613755576136ee89838888878181106136ce577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b90506020020160208101906136e39190614856565b6135c7906001614b4d565b15613755576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f427261636b6574206d7573742062652068696768657200000000000000000000604482015260640161072b565b61375f8185614b35565b93505050808061376e90614d51565b9150506132a8565b50613781338261402d565b6040805182815260208101869052879133917f0f5fca62da8fb5d95525b49e5eaa7b20bc6bd9e2f6b64b493442d1c0bd6ef486910160405180910390a3506137c96001600055565b5050505050565b6137d8613e34565b73ffffffffffffffffffffffffffffffffffffffff8316613855576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f43616e6e6f74206265207a65726f206164647265737300000000000000000000604482015260640161072b565b73ffffffffffffffffffffffffffffffffffffffff82166138d2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f43616e6e6f74206265207a65726f206164647265737300000000000000000000604482015260640161072b565b73ffffffffffffffffffffffffffffffffffffffff811661394f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f43616e6e6f74206265207a65726f206164647265737300000000000000000000604482015260640161072b565b6003805473ffffffffffffffffffffffffffffffffffffffff8581167fffffffffffffffffffffffff0000000000000000000000000000000000000000928316811790935560048054868316908416811790915560028054928616929093168217909255604080519384526020840192909252908201527f3e945b7660001d46cfd5e729545f7f0b6c65bdee54066a91c7acad703f1b731e9060600160405180910390a1505050565b60015473ffffffffffffffffffffffffffffffffffffffff16331480613a35575060025473ffffffffffffffffffffffffffffffffffffffff1633145b613a9b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f7220696e6a6563746f720000000000000000000000604482015260640161072b565b60016000828152600c602052604090205460ff166003811115613ae7577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b14613b4e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4c6f7474657279206e6f74206f70656e00000000000000000000000000000000604482015260640161072b565b60003411613bb8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d75737420696e6a65637420706f73697469766520616d6f756e740000000000604482015260640161072b565b6000818152600c60205260408120601a018054349290613bd9908490614b35565b909155505060405134815281907f1bbd659dd628a25f7ff2eabb69c74a56939c539728282275c1c9c1a2d3e340499060200160405180910390a250565b613c1e613e34565b73ffffffffffffffffffffffffffffffffffffffff8116613cc1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161072b565b61205281613f42565b60008382613cd9826001614b35565b613ce39190614ce9565b613ced8486614cac565b613cf79190614cac565b610f3a9190614b75565b6000838152600c60209081526040808320601b0154858452600d90925282205463ffffffff918216911682613d37856001614b4d565b613d4290600a614bd0565b613d4c9084614dae565b63ffffffff8087166000908152600e6020526040902054613d6e929116614b4d565b90506000613d7d866001614b4d565b613d8890600a614bd0565b613d929084614dae565b63ffffffff8088166000908152600e6020526040902054613db4929116614b4d565b90508063ffffffff168263ffffffff161415613e27576000888152600c602081905260409091200163ffffffff871660068110613e1a577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b0154945050505050610f3d565b6000945050505050610f3d565b60015473ffffffffffffffffffffffffffffffffffffffff163314611046576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161072b565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526117ce90849061416f565b6001805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60026000541415614026576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161072b565b6002600055565b60008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114614087576040519150601f19603f3d011682016040523d82523d6000602084013e61408c565b606091505b505090508061411d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f5472616e7366657248656c7065723a20535f5452414e534645525f4641494c4560448201527f4400000000000000000000000000000000000000000000000000000000000000606482015260840161072b565b60405182815273ffffffffffffffffffffffffffffffffffffffff84169030907f3aee93130a536584ec9670aae8663c7be527a75ed5b14099c0e25503627d6b549060200160405180910390a3505050565b60006141d1826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff1661427e9092919063ffffffff16565b90508051600014806141f25750808060200190518101906141f29190614649565b6117ce576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161072b565b6060610f3a8484600085856000808673ffffffffffffffffffffffffffffffffffffffff1685876040516142b29190614963565b60006040518083038185875af1925050503d80600081146142ef576040519150601f19603f3d011682016040523d82523d6000602084013e6142f4565b606091505b509150915061430587838387614312565b925050505b949350505050565b606083156143a557825161439e5773ffffffffffffffffffffffffffffffffffffffff85163b61439e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161072b565b508161430a565b61430a83838151156143ba5781518083602001fd5b806040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161072b9190614a21565b604080516101a081019091528060008152602001600081526020016000815260200160008152602001600081526020016144266144ad565b81526020016000815260200161443a6144ad565b81526020016144476144ad565b8152602001600081526020016000815260200160008152602001600063ffffffff1681525090565b826006810192821561449d579160200282015b8281111561449d578251825591602001919060010190614482565b506144a99291506144cb565b5090565b6040518060c001604052806006906020820280368337509192915050565b5b808211156144a957600081556001016144cc565b803573ffffffffffffffffffffffffffffffffffffffff8116811461450457600080fd5b919050565b60008083601f84011261451a578182fd5b50813567ffffffffffffffff811115614531578182fd5b6020830191508360208260051b8501011115611aa457600080fd5b60006020828403121561455d578081fd5b61082b826144e0565b60008060006060848603121561457a578182fd5b614583846144e0565b9250614591602085016144e0565b915061459f604085016144e0565b90509250925092565b600080604083850312156145ba578182fd5b6145c3836144e0565b946020939093013593505050565b600080600080608085870312156145e6578081fd5b6145ef856144e0565b966020860135965060408601359560600135945092505050565b6000806020838503121561461b578182fd5b823567ffffffffffffffff811115614631578283fd5b61463d85828601614509565b90969095509350505050565b60006020828403121561465a578081fd5b8151610f3d81614e2f565b600060208284031215614676578081fd5b5035919050565b60006020828403121561468e578081fd5b5051919050565b6000806000806000606086880312156146ac578081fd5b85359450602086013567ffffffffffffffff808211156146ca578283fd5b6146d689838a01614509565b909650945060408801359150808211156146ee578283fd5b506146fb88828901614509565b969995985093965092949392505050565b600080600060408486031215614720578283fd5b83359250602084013567ffffffffffffffff81111561473d578283fd5b61474986828701614509565b9497909650939450505050565b60008060408385031215614768578182fd5b82359150602083013561477a81614e2f565b809150509250929050565b60008060408385031215614797578182fd5b50508035926020909101359150565b6000806000606084860312156147ba578283fd5b505081359360208301359350604090920135919050565b600080600080600061014086880312156147e9578283fd5b85359450602086013593506040860135925061012086018781111561480c578182fd5b94979396509194606001933592915050565b600080600060608486031215614832578081fd5b8335925060208401359150604084013561484b81614e3d565b809150509250925092565b600060208284031215614867578081fd5b8135610f3d81614e3d565b600060208284031215614883578081fd5b8151610f3d81614e3d565b6000815180845260208085019450808401835b838110156148bf5781511515875295820195908201906001016148a1565b509495945050505050565b8060005b60068110156148ed5781518452602093840193909101906001016148ce565b50505050565b6000815180845260208085019450808401835b838110156148bf57815163ffffffff1687529582019590820190600101614906565b6004811061495f577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b60008251614975818460208701614d25565b9190910192915050565b6080808252855190820181905260009060209060a0840190828901845b828110156149b85781518452928401929084019060010161499c565b505050838103828501526149cc81886148f3565b91505082810360408401526149e1818661488e565b91505082606083015295945050505050565b604081526000614a0660408301856148f3565b8281036020840152614a18818561488e565b95945050505050565b6020815260008251806020840152614a40816040850160208701614d25565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b600061038082019050614a86828451614928565b6020830151602083015260408301516040830152606083015160608301526080830151608083015260a0830151614ac060a08401826148ca565b5060c0830151610160818185015260e08501519150610180614ae4818601846148ca565b6101008601519250614afa6102408601846148ca565b6101208601516103008601526101408601516103208601529085015161034085015284015163ffffffff811661036085015290505092915050565b60008219821115614b4857614b48614dd1565b500190565b600063ffffffff808316818516808303821115614b6c57614b6c614dd1565b01949350505050565b600082614b8457614b84614e00565b500490565b60018163ffffffff825b80861115614bc757828204831115614bad57614bad614dd1565b80861615614bba57928202925b94851c9491800291614b93565b50509250929050565b600063ffffffff61430a818516828516600082614bef5750600161082e565b81614bfc5750600061082e565b8160018114614c125760028114614c1c57614c4d565b600191505061082e565b60ff841115614c2d57614c2d614dd1565b6001841b915063ffffffff821115614c4757614c47614dd1565b5061082e565b5060208310610133831016604e8410600b8410161715614c84575081810a63ffffffff811115614c7f57614c7f614dd1565b61082e565b614c8e8383614b89565b8063ffffffff04821115614ca457614ca4614dd1565b029392505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615614ce457614ce4614dd1565b500290565b600082821015614cfb57614cfb614dd1565b500390565b600063ffffffff83811690831681811015614d1d57614d1d614dd1565b039392505050565b60005b83811015614d40578181015183820152602001614d28565b838111156148ed5750506000910152565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415614d8357614d83614dd1565b5060010190565b600063ffffffff80831681811415614da457614da4614dd1565b6001019392505050565b600063ffffffff80841680614dc557614dc5614e00565b92169190910692915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b801515811461205257600080fd5b63ffffffff8116811461205257600080fdfea2646970667358221220cff41e03b1bc4bd911a102e6ab2adc67a0dcdb674cb40e64b0b5fd92d96b8b8364736f6c63430008040033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000330a1a59604b838c26e1aaf25dd5dc1c1ddc545a
-----Decoded View---------------
Arg [0] : _randomGeneratorAddress (address): 0x330A1A59604b838c26E1aAf25dD5Dc1C1dDC545a
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000330a1a59604b838c26e1aaf25dd5dc1c1ddc545a
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in S
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.