This nametag was submitted by Kleros Curate.
Overview
ETH Balance
0 ETH
Eth Value
$0.00Token Holdings
More Info
Private Name Tags
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
0x37c8e34320a063cc57418d998f6b8822124000a7835c29a690050fd4ab5c56a4 | Buy Entry | (pending) | 8 days ago | IN | 0 ETH | (Pending) | |||
Buy Entry | 20496012 | 135 days ago | IN | 0 ETH | 0.00003395 | ||||
Buy Entry | 20452800 | 141 days ago | IN | 0 ETH | 0.00004592 | ||||
Buy Entry | 20101239 | 190 days ago | IN | 0 ETH | 0.00004651 | ||||
Buy Entry | 19899979 | 218 days ago | IN | 0 ETH | 0.00011572 | ||||
Buy Entry | 19837099 | 227 days ago | IN | 0 ETH | 0.00007135 | ||||
Buy Entry | 19836963 | 227 days ago | IN | 0 ETH | 0.00007135 | ||||
Buy Entry | 19836944 | 227 days ago | IN | 0 ETH | 0.00007135 | ||||
Buy Entry | 19836934 | 227 days ago | IN | 0 ETH | 0.00007135 | ||||
Buy Entry | 19836920 | 227 days ago | IN | 0 ETH | 0.00007135 | ||||
Buy Entry | 19836916 | 227 days ago | IN | 0 ETH | 0.00007135 | ||||
Buy Entry | 19836902 | 227 days ago | IN | 0 ETH | 0.00007135 | ||||
Buy Entry | 19814832 | 230 days ago | IN | 0 ETH | 0.00007556 | ||||
Buy Entry | 19784815 | 234 days ago | IN | 0 ETH | 0.00026985 | ||||
Buy Entry | 19750104 | 239 days ago | IN | 0 ETH | 0.00027434 | ||||
Buy Entry | 19750103 | 239 days ago | IN | 0 ETH | 0.00048371 | ||||
Buy Entry | 19750103 | 239 days ago | IN | 0 ETH | 0.00025409 | ||||
Buy Entry | 19749135 | 239 days ago | IN | 0 ETH | 0.00018369 | ||||
Buy Entry | 18301023 | 442 days ago | IN | 0 ETH | 0.00021352 | ||||
Buy Entry | 18295226 | 443 days ago | IN | 0 ETH | 0.00011886 | ||||
Buy Entry | 18295120 | 443 days ago | IN | 0 ETH | 0.00011893 | ||||
Buy Entry | 18289916 | 443 days ago | IN | 0 ETH | 0.00011893 | ||||
Buy Entry | 18289903 | 443 days ago | IN | 0 ETH | 0.00011893 | ||||
Buy Entry | 18289718 | 444 days ago | IN | 0 ETH | 0.00011886 | ||||
Buy Entry | 18289718 | 444 days ago | IN | 0 ETH | 0.00011893 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
17274496 | 586 days ago | 155.514 ETH | ||||
17274496 | 586 days ago | 150 ETH | ||||
17115152 | 608 days ago | 1 ETH | ||||
17115152 | 608 days ago | 1 ETH | ||||
17115151 | 608 days ago | 1 ETH | ||||
17115151 | 608 days ago | 1 ETH | ||||
17115150 | 608 days ago | 0.5 ETH | ||||
17115149 | 608 days ago | 0.5 ETH | ||||
17115149 | 608 days ago | 0.5 ETH | ||||
17115148 | 608 days ago | 0.5 ETH | ||||
17115148 | 608 days ago | 0.5 ETH | ||||
17091390 | 612 days ago | 1.095 ETH | ||||
17091390 | 612 days ago | 1 ETH | ||||
17088758 | 612 days ago | 0.445 ETH | ||||
17088758 | 612 days ago | 0.5 ETH | ||||
17082276 | 613 days ago | 0.9 ETH | ||||
17082276 | 613 days ago | 1 ETH | ||||
17081858 | 613 days ago | 1 ETH | ||||
17080503 | 613 days ago | 0.5 ETH | ||||
17080503 | 613 days ago | 0.5 ETH | ||||
17078736 | 614 days ago | 0.56 ETH | ||||
17078736 | 614 days ago | 0.5 ETH | ||||
17076960 | 614 days ago | 0.84 ETH | ||||
17076960 | 614 days ago | 1 ETH | ||||
17075181 | 614 days ago | 1.14 ETH |
Loading...
Loading
Contract Name:
CompetitionETHAsPrize
Compiler Version
v0.8.4+commit.c7e474f2
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.4; import "@openzeppelin/contracts/access/AccessControl.sol"; import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "@chainlink/contracts/src/v0.8/VRFConsumerBase.sol"; import "@openzeppelin/contracts/utils/math/Math.sol"; import "./BlackListManager.sol"; /// @title Raffles manager /// @author Luis Pando /// @notice It consumes VRF v1 from Chainlink. It has the role /// "operator" that is the one used by a backend app to make some calls /// @dev It saves in an ordered array the player wallet and the current /// entries count. So buying entries has a complexity of O(1) /// For calculating the winner, from the huge random number generated by Chainlink /// a normalized random is generated by using the module method, adding 1 to have /// a random from 1 to entriesCount. /// So next step is to perform a binary search on the ordered array to get the /// player O(log n) /// Example: /// 0 -> { 1, player1} as player1 buys 1 entry /// 1 -> {51, player2} as player2 buys 50 entries /// 2 -> {52, player3} as player3 buys 1 entry /// 3 -> {53, player4} as player4 buys 1 entry /// 4 -> {153, player5} as player5 buys 100 entries /// So the setWinner method performs a binary search on that sorted array to get the upper bound. /// If the random number generated is 150, the winner is player5. If the random number is 20, winner is player2 contract CompetitionETHAsPrize is AccessControl, ReentrancyGuard, VRFConsumerBase { ////////// CHAINLINK VRF v1 ///////////////// bytes32 internal keyHash; // chainlink uint256 internal fee; // fee paid in LINK to chainlink. 0.1 in Rinkeby, 2 in mainnet struct RandomResult { uint256 randomNumber; // random number generated by chainlink. uint256 nomalizedRandomNumber; // random number % entriesLength + 1. So between 1 and entries.length } // event sent when the random number is generated by the VRF event RandomNumberCreated( uint256 indexed idFromMetawin, uint256 randomNumber, uint256 normalizedRandomNumber ); struct RaffleInfo { uint256 id; // raffleId uint256 size; // length of the entries array of that raffle } mapping(uint256 => RandomResult) public requests; // map the requestId created by chainlink with the raffle info passed as param when calling getRandomNumber() mapping(bytes32 => RaffleInfo) public chainlinkRaffleInfo; /////////////// END CHAINKINK VRF V1 ////////////// // Event sent when the raffle is created by the operator event RaffleCreated(uint256 indexed raffleId, uint256 indexed prizeAmount); // Event sent when the ETH is staked event RaffleStarted(uint256 indexed raffleId, address indexed seller); // Event sent when the raffle is finished (either early cashout or successful completion) event RaffleEnded( uint256 indexed raffleId, address indexed winner, uint256 amountRaised, uint256 randomNumber ); // Event sent when one or more entries are sold (info from the price structure) event EntrySold( uint256 indexed raffleId, address indexed buyer, uint256 currentSize, uint256 priceStructureId ); // Event sent when a free entry is added by the operator event FreeEntry( uint256 indexed raffleId, address[] buyer, uint256 amount, uint256 currentSize ); // Event sent when a raffle is asked to cancel by the operator event RaffleCancelled(uint256 indexed raffleId, uint256 amountRaised); // The raffle is closed successfully and the platform receives the fee event FeeTransferredToPlatform( uint256 indexed raffleId, uint256 amountTransferred ); // When the raffle is asked to be cancelled and 30 days have passed, the operator can call a method // to transfer the remaining funds and this event is emitted event RemainingFundsTransferred( uint256 indexed raffleId, uint256 amountInWeis ); // When the raffle is asked to be cancelled and 30 days have not passed yet, the players can call a // method to refund the amount spent on the raffle and this event is emitted event Refund( uint256 indexed raffleId, uint256 amountInWeis, address indexed player ); event EarlyCashoutTriggered(uint256 indexed raffleId, uint256 amountRaised); event SetWinnerTriggered(uint256 indexed raffleId, uint256 amountRaised); event StatusChangedInEmergency(uint256 indexed raffleId, uint256 newStatus); // Emitted when an entry is cancelled event EntryCancelled(uint256 indexed raffleId, uint256 amountOfEntriesCanceled, address player); /* every raffle has an array of price structure (max size = 5) with the different prices for the different entries bought. The price for 1 entry is different than for 5 entries where there is a discount*/ struct PriceStructure { uint256 id; uint256 numEntries; uint256 price; } mapping(uint256 => PriceStructure[5]) public prices; // Every raffle has a funding structure. struct FundingStructure { uint256 minimumFundsInWeis; uint256 desiredFundsInWeis; } mapping(uint256 => FundingStructure) public fundingList; // In order to calculate the winner, in this struct is saved for each bought the data struct EntriesBought { uint256 currentEntriesLength; // current amount of entries bought in the raffle address player; // wallet address of the player } // every raffle has a sorted array of EntriesBought. Each element is created when calling // either buyEntry or giveBatchEntriesForFree mapping(uint256 => EntriesBought[]) public entriesList; // Main raffle data struct struct RaffleStruct { STATUS status; // status of the raffle. Can be created, accepted, ended, etc uint256 maxEntries; // maximum number of entries allowed per user, to avoid abuse uint256 amountOfETH; // Amount of ETH of the prize address winner; // address of thed winner of the raffle. Address(0) if no winner yet uint256 randomNumber; // normalized (0-Entries array size) random number generated by the VRF uint256 amountRaised; // funds raised so far in wei address seller; // address of the seller of the ETH uint256 platformPercentage; // percentage of the funds raised that goes to the platform uint256 entriesLength; // to easy frontend, the length of the entries array is saved here uint256 cancellingDate; address[] collectionWhitelist; // addresses of the required nfts. Will be empty if no NFT is required to buy ENTRY_TYPE entryType; } // The main structure is an array of raffles RaffleStruct[] public raffles; // Map that contains the number of entries each user has bought, to prevent abuse, and the claiming info struct ClaimStruct { uint256 numEntriesPerUser; uint256 amountSpentInWeis; bool claimed; } mapping(bytes32 => ClaimStruct) public claimsData; // Map with the addresses linked to a particular raffle + nft mapping(bytes32 => address) public requiredNFTWallets; // All the different status a rafVRFCoordinatorfle can have enum STATUS { CREATED, // the operator creates the raffle ACCEPTED, // the seller stakes the eth for the raffle EARLY_CASHOUT, // the seller wants to cashout early CANCELLED, // the operator cancels the raffle and transfer the remaining funds after 30 days passes CLOSING_REQUESTED, // the operator sets a winner ENDED, // the raffle is finished, and funds were transferred CANCEL_REQUESTED // operator asks to cancel the raffle. Players has 30 days to ask for a refund } enum ENTRY_TYPE { ONLY_DIRECTLY, ONLY_EXTERNAL_CONTRACT, MIXED } // The operator role is operated by a backend application bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR"); // requested by Hamburger. Role for the buy method of the hamburger (only that contract) bytes32 public constant MINTERCONTRACT_ROLE = keccak256("MINTERCONTRACT"); // address of the wallet controlled by the platform that will receive the platform fee address payable public destinationWallet = payable(0xEda703919A528481F4F11423a728300dCaBF441F); // contract that contains the black list BlackListManager blackListManager; constructor( address _blacklistManager, address _vrfCoordinator, address _linkToken, bytes32 _keyHash, bool _mainetFee ) VRFConsumerBase( _vrfCoordinator, // VRF Coordinator _linkToken // LINK Token ) { _setupRole(OPERATOR_ROLE, 0x13503B622abC0bD30A7e9687057DF6E8c42Fb928); _setupRole(DEFAULT_ADMIN_ROLE, msg.sender); keyHash = _keyHash; if (_mainetFee == true) fee = 2 * 10**18; // in mainnet, the fee must be 2 LINK else fee = 0.1 * 10**18; // 0.1 LINK In Rinkeby and Goerli blackListManager = BlackListManager(_blacklistManager); } /// @dev this is the method that will be called by the smart contract to get a random number /// @param _id Id of the raffle /// @param _entriesSize length of the entries array of that raffle /// @return requestId Id generated by chainlink function getRandomNumber(uint256 _id, uint256 _entriesSize) internal returns (bytes32 requestId) { require( LINK.balanceOf(address(this)) >= fee, "Not enough LINK - fill contract with faucet" ); bytes32 result = requestRandomness(keyHash, fee); // result is the requestId generated by chainlink. It is saved in a map linked to the param id chainlinkRaffleInfo[result] = RaffleInfo({id: _id, size: _entriesSize}); return result; } /// @dev Callback function used by VRF Coordinator. Is called by chainlink /// the random number generated is normalized to the size of the entries array, and an event is /// generated, that will be listened by the platform backend to be checked if corresponds to a /// member of the MW community, and if true will call transferFunds /// @param requestId id generated previously (on method getRandomNumber by chainlink) /// @param randomness random number (huge) generated by chainlink function fulfillRandomness(bytes32 requestId, uint256 randomness) internal override { // randomness is the actual random number. Now extract from the aux map the original param id of the call RaffleInfo memory raffleInfo = chainlinkRaffleInfo[requestId]; // save the random number on the map with the original id as key uint256 normalizedRandomNumber = (randomness % raffleInfo.size) + 1; RandomResult memory result = RandomResult({ randomNumber: randomness, nomalizedRandomNumber: normalizedRandomNumber }); requests[raffleInfo.id] = result; // send the event with the original id and the random number emit RandomNumberCreated( raffleInfo.id, randomness, normalizedRandomNumber ); transferFunds(raffleInfo.id, normalizedRandomNumber); } ////////////////////////////////////////////// /// @param _desiredFundsInWeis the amount the seller would like to get from the raffle /// @param _maxEntriesPerUser To avoid whales, the number of entries an user can have is limited /// @param _amountOfETH Amount of ETH of the prize /// @param _minimumFundsInWeis The mininum amount required for the raffle to set a winner /// @param _prices Array of prices and amount of entries the customer could purchase /// @param _commissionInBasicPoints commission for the platform, in basic points /// @param _collectionWhitelist array with the required collections to participate in the raffle. Empty if there is no collection /// @param _entryType enum with the kind of entry ONLY_DIRECTLY, ONLY_EXTERNAL_CONTRACT or BOTH /// @notice Creates a raffle /// @dev creates a raffle struct and push it to the raffles array. Some data is stored in the funding data structure /// sends an event when finished /// @return raffleId function createRaffle( uint256 _desiredFundsInWeis, uint256 _maxEntriesPerUser, uint256 _amountOfETH, uint256 _minimumFundsInWeis, PriceStructure[] calldata _prices, uint256 _commissionInBasicPoints, address[] calldata _collectionWhitelist, ENTRY_TYPE _entryType ) external onlyRole(OPERATOR_ROLE) returns (uint256) { require(_maxEntriesPerUser > 0, "maxEntries is 0"); require(_amountOfETH > 0, "Prize is 0"); require(_commissionInBasicPoints <= 5000, "commission too high"); RaffleStruct memory raffle = RaffleStruct({ status: STATUS.CREATED, maxEntries: _maxEntriesPerUser, amountOfETH: _amountOfETH, winner: address(0), randomNumber: 0, amountRaised: 0, seller: msg.sender, platformPercentage: _commissionInBasicPoints, entriesLength: 0, cancellingDate: 0, collectionWhitelist: _collectionWhitelist, entryType: _entryType }); raffles.push(raffle); require(_prices.length > 0, "No prices"); for (uint256 i = 0; i < _prices.length; i++) { require(_prices[i].numEntries > 0, "numEntries is 0"); PriceStructure memory p = PriceStructure({ id: _prices[i].id, numEntries: _prices[i].numEntries, price: _prices[i].price }); prices[raffles.length - 1][i] = p; } fundingList[raffles.length - 1] = FundingStructure({ minimumFundsInWeis: _minimumFundsInWeis, desiredFundsInWeis: _desiredFundsInWeis }); emit RaffleCreated(raffles.length - 1, _amountOfETH); return raffles.length - 1; } /* * Example of a price structure: 1 ticket 0.02 5 tickets 0.018 (10% discount) 10 tickets 0.16 (20% discount) 25 tickets 0.35 (30% discount) 50 tickets 0.6 (40% discount) */ /// @param _idRaffle raffleId /// @param _id Id of the price structure /// @return the price structure of that particular Id + raffle /// @dev Returns the price structure, used in the frontend function getPriceStructForId(uint256 _idRaffle, uint256 _id) internal view returns (PriceStructure memory) { for (uint256 i = 0; i < 5; i++) { if (prices[_idRaffle][i].id == _id) { return prices[_idRaffle][i]; } } return PriceStructure({id: 0, numEntries: 0, price: 0}); } /// @param _raffleId Id of the raffle /// @dev Anyone can stake. The owner must have approved this contract before. Otherwise will revert when transferring from the owner function stakeETH(uint256 _raffleId) external payable nonReentrant { RaffleStruct storage raffle = raffles[_raffleId]; // Check if the raffle is already created require(raffle.status == STATUS.CREATED, "Raffle not CREATED"); // check the amount staked is the correct require(raffle.amountOfETH == msg.value, "Prize not staked"); raffle.status = STATUS.ACCEPTED; raffle.seller = msg.sender; emit RaffleStarted(_raffleId, msg.sender); } /// @dev callable by players. Depending on the number of entries assigned to the price structure the player buys (_id parameter) /// one or more entries will be assigned to the player. /// Also it is checked the maximum number of entries per user is not reached /// As the method is payable, in msg.value there will be the amount paid by the user /// @notice If the operator set requiredNFTs when creating the raffle, only the owners of nft on that collection can make a call to this method. This will be /// used for special raffles /// @param _raffleId: id of the raffle /// @param _id: id of the price structure /// @param _collection: collection of the tokenId used. Not used if there is no required nft on the raffle /// @param _tokenIdUsed: id of the token used in private raffles (to avoid abuse can not be reused on the same raffle) function buyEntry( uint256 _raffleId, uint256 _id, address _collection, uint256 _tokenIdUsed ) external payable nonReentrant { RaffleStruct storage raffle = raffles[_raffleId]; require(raffle.seller != msg.sender, "Seller cannot buy"); require( raffle.entryType == ENTRY_TYPE.MIXED || raffle.entryType == ENTRY_TYPE.ONLY_DIRECTLY, "Entry type not allowed" ); require( blackListManager.isBlackListed(msg.sender) == false, "Blacklisted!" ); // if the raffle requires an nft if (raffle.collectionWhitelist.length > 0) { bool hasRequiredCollection = false; for (uint256 i = 0; i < raffle.collectionWhitelist.length; i++) { if (raffle.collectionWhitelist[i] == _collection) { hasRequiredCollection = true; break; } } require( hasRequiredCollection == true, "Not in required collection" ); IERC721 requiredNFT = IERC721(_collection); require( requiredNFT.ownerOf(_tokenIdUsed) == msg.sender, "Not the owner of tokenId" ); bytes32 hashRequiredNFT = keccak256( abi.encode(_collection, _raffleId, _tokenIdUsed) ); // check the tokenId has not been using yet in the raffle, to avoid abuse if (requiredNFTWallets[hashRequiredNFT] == address(0)) { requiredNFTWallets[hashRequiredNFT] = msg.sender; } else require( requiredNFTWallets[hashRequiredNFT] == msg.sender, "tokenId used" ); } require(msg.sender != address(0), "msg.sender is null"); // 37 require(_id > 0, "howMany is 0"); require(raffle.status == STATUS.ACCEPTED, "Raffle is not in accepted"); // 1808 PriceStructure memory priceStruct = getPriceStructForId(_raffleId, _id); require(priceStruct.numEntries > 0, "id not supported"); require( msg.value == priceStruct.price, "msg.value must be equal to the price" ); // 1722 bytes32 hash = keccak256(abi.encode(msg.sender, _raffleId)); // check there are enough entries left for this particular user require( claimsData[hash].numEntriesPerUser + priceStruct.numEntries <= raffle.maxEntries, "Bought too many entries" ); EntriesBought memory entryBought = EntriesBought({ player: msg.sender, currentEntriesLength: raffle.entriesLength + priceStruct.numEntries }); entriesList[_raffleId].push(entryBought); raffle.amountRaised += msg.value; // 6917 gas // update the field entriesLength, used in frontend to avoid making extra calls raffle.entriesLength = raffle.entriesLength + priceStruct.numEntries; //update claim data claimsData[hash].numEntriesPerUser += priceStruct.numEntries; claimsData[hash].amountSpentInWeis += msg.value; emit EntrySold(_raffleId, msg.sender, raffle.entriesLength, _id); // 2377 } // The operator can add free entries to the raffle /// @param _raffleId Id of the raffle /// @param _freePlayers array of addresses corresponding to the wallet of the users that won a free entrie /// @dev only operator can make this call. Assigns a single entry per user, except if that user already reached the max limit of entries per user function giveBatchEntriesForFree( uint256 _raffleId, address[] memory _freePlayers ) external nonReentrant onlyRole(OPERATOR_ROLE) { require( raffles[_raffleId].status == STATUS.ACCEPTED, "Raffle is not in accepted" ); uint256 freePlayersLength = _freePlayers.length; uint256 validPlayersCount = 0; for (uint256 i = 0; i < freePlayersLength; i++) { address entry = _freePlayers[i]; if ( claimsData[keccak256(abi.encode(entry, _raffleId))] .numEntriesPerUser + 1 <= raffles[_raffleId].maxEntries ) { // add a new element to the entriesBought array. // as this method only adds 1 entry per call, the amountbought is always 1 EntriesBought memory entryBought = EntriesBought({ player: entry, currentEntriesLength: raffles[_raffleId].entriesLength + i + 1 }); entriesList[_raffleId].push(entryBought); claimsData[keccak256(abi.encode(entry, _raffleId))] .numEntriesPerUser++; ++validPlayersCount; } } raffles[_raffleId].entriesLength = raffles[_raffleId].entriesLength + validPlayersCount; emit FreeEntry( _raffleId, _freePlayers, freePlayersLength, raffles[_raffleId].entriesLength ); } // helper method to get the winner address of a raffle /// @param _raffleId Id of the raffle /// @param _normalizedRandomNumber Generated by chainlink /// @return the wallet that won the raffle /// @dev Uses a binary search on the sorted array to retreive the winner /// but if the winner candidate is blacklisted, loop through the left looking for /// a candidate not blacklisted function getWinnerAddressFromRandom( uint256 _raffleId, uint256 _normalizedRandomNumber ) public view returns (address) { uint256 position = findUpperBound( entriesList[_raffleId], _normalizedRandomNumber ); address candidate = entriesList[_raffleId][position].player; // general case if (candidate != address(0)) return candidate; // special case. The user is blacklisted, so try next on the left until find a non-blacklisted else { bool ended = false; uint256 i = position; while ( ended == false && entriesList[_raffleId][i].player == address(0) ) { if (i == 0) i = entriesList[_raffleId].length - 1; else i = i - 1; // we came to the beginning without finding a non blacklisted player if (i == position) ended == true; } require(!ended, "All users blacklisted"); return entriesList[_raffleId][i].player; } } /// @param array sorted array of EntriesBought. CurrentEntriesLength is the numeric field used to sort /// @param element uint256 to find. Goes from 1 to entriesLength /// @dev based on openzeppelin code (v4.0), modified to use an array of EntriesBought /// Searches a sorted array and returns the first index that contains a value greater or equal to element. /// If no such index exists (i.e. all values in the array are strictly less than element), the array length is returned. Time complexity O(log n). /// array is expected to be sorted in ascending order, and to contain no repeated elements. /// https://docs.openzeppelin.com/contracts/3.x/api/utils#Arrays-findUpperBound-uint256---uint256- function findUpperBound(EntriesBought[] storage array, uint256 element) internal view returns (uint256) { if (array.length == 0) { return 0; } uint256 low = 0; uint256 high = array.length; while (low < high) { uint256 mid = Math.average(low, high); // Note that mid will always be strictly less than high (i.e. it will be a valid array index) // because Math.average rounds down (it does integer division with truncation). if (array[mid].currentEntriesLength > element) { high = mid; } else { low = mid + 1; } } // At this point `low` is the exclusive upper bound. We will return the inclusive upper bound. if (low > 0 && array[low - 1].currentEntriesLength == element) { return low - 1; } else { return low; } } // The operator can call this method once they receive the event "RandomNumberCreated" // triggered by the VRF v1 consumer contract (RandomNumber.sol) /// @param _raffleId Id of the raffle /// @param _normalizedRandomNumber index of the array that contains the winner of the raffle. Generated by chainlink /// @notice it is the method that sets the winner and transfers funds /// @dev called by Chainlink callback function transferFunds(uint256 _raffleId, uint256 _normalizedRandomNumber) internal nonReentrant { RaffleStruct storage raffle = raffles[_raffleId]; // Only when the raffle has been asked to be closed and the platform require( raffle.status == STATUS.EARLY_CASHOUT || raffle.status == STATUS.CLOSING_REQUESTED, "Raffle in wrong status" ); raffle.randomNumber = _normalizedRandomNumber; raffle.winner = getWinnerAddressFromRandom( _raffleId, _normalizedRandomNumber ); raffle.status = STATUS.ENDED; (bool sentPrize, ) = raffle.winner.call{value: raffle.amountOfETH}(""); require(sentPrize, "Failed to send Ether"); uint256 amountForPlatform = (raffle.amountRaised * raffle.platformPercentage) / 10000; uint256 amountForSeller = raffle.amountRaised - amountForPlatform; // transfer amount (75%) to the seller. (bool sent, ) = raffle.seller.call{value: amountForSeller}(""); require(sent, "Failed to send Ether"); // transfer the amount to the platform (bool sent2, ) = destinationWallet.call{value: amountForPlatform}(""); require(sent2, "Failed send Eth to MW"); emit FeeTransferredToPlatform(_raffleId, amountForPlatform); emit RaffleEnded( _raffleId, raffle.winner, raffle.amountRaised, _normalizedRandomNumber ); } // can be called by the seller at every moment once enough funds has been raised /// @param _raffleId Id of the raffle /// @notice the seller of the ETH, if the minimum amount has been reached, can call an early cashout, finishing the raffle /// @dev it triggers Chainlink VRF1 consumer, and generates a random number that is normalized and checked that corresponds to a MW player function earlyCashOut(uint256 _raffleId) external { RaffleStruct storage raffle = raffles[_raffleId]; FundingStructure memory funding = fundingList[_raffleId]; require(raffle.seller == msg.sender, "Not the seller"); // Check if the raffle is already accepted require( raffle.status == STATUS.ACCEPTED, "Raffle not in accepted status" ); require( raffle.amountRaised >= funding.minimumFundsInWeis, "Not enough funds raised" ); raffle.status = STATUS.EARLY_CASHOUT; getRandomNumber(_raffleId, raffle.entriesLength); emit EarlyCashoutTriggered(_raffleId, raffle.amountRaised); } /// @param _raffleId Id of the raffle /// @notice the operator finish the raffle, if the desired funds has been reached /// @dev it triggers Chainlink VRF1 consumer, and generates a random number that is normalized and checked that corresponds to a MW player function setWinner(uint256 _raffleId) external nonReentrant onlyRole(OPERATOR_ROLE) { RaffleStruct storage raffle = raffles[_raffleId]; FundingStructure storage funding = fundingList[_raffleId]; // Check if the raffle is already accepted or is called again because early cashout failed require(raffle.status == STATUS.ACCEPTED, "Raffle in wrong status"); require( raffle.amountRaised >= funding.minimumFundsInWeis, "Not enough funds raised" ); require( funding.desiredFundsInWeis <= raffle.amountRaised, "Desired funds not raised" ); raffle.status = STATUS.CLOSING_REQUESTED; // this call trigers the VRF v1 process from Chainlink getRandomNumber(_raffleId, raffle.entriesLength); emit SetWinnerTriggered(_raffleId, raffle.amountRaised); } /// @param _newAddress new address of the platform /// @dev Change the wallet of the platform. The one that will receive the platform fee when the raffle is closed. /// Only the admin can change this function setDestinationAddress(address payable _newAddress) external onlyRole(DEFAULT_ADMIN_ROLE) { destinationWallet = _newAddress; } /// @param _raffleId Id of the raffle /// @dev The operator can cancel the raffle. The ETH is sent back to the seller /// The raised funds are send to the destination wallet. The buyers will /// be refunded offchain in the metawin wallet function cancelRaffle(uint256 _raffleId) external nonReentrant onlyRole(OPERATOR_ROLE) { RaffleStruct storage raffle = raffles[_raffleId]; //FundingStructure memory funding = fundingList[_raffleId]; // Dont cancel twice, or cancel an already ended raffle require( raffle.status != STATUS.ENDED && raffle.status != STATUS.CANCELLED && raffle.status != STATUS.EARLY_CASHOUT && raffle.status != STATUS.CLOSING_REQUESTED && raffle.status != STATUS.CANCEL_REQUESTED, "Wrong status" ); // only if the raffle is in accepted status the ETH is staked and could have entries sold if (raffle.status == STATUS.ACCEPTED) { // transfer eth to the owner (bool sentPrize, ) = raffle.seller.call{value: raffle.amountOfETH}( "" ); require(sentPrize, "Failed to send Ether"); } raffle.status = STATUS.CANCEL_REQUESTED; raffle.cancellingDate = block.timestamp; emit RaffleCancelled(_raffleId, raffle.amountRaised); } /// @param _raffleId Id of the raffle /// @dev The player can claim a refund during the first 30 days after the raffle was cancelled /// in the map "ClaimsData" it is saves how much the player spent on that raffle, as they could /// have bought several entries function claimRefund(uint256 _raffleId) external nonReentrant { RaffleStruct storage raffle = raffles[_raffleId]; require(raffle.status == STATUS.CANCEL_REQUESTED, "wrong status"); require( block.timestamp <= raffle.cancellingDate + 30 days, "claim time expired" ); ClaimStruct storage claimData = claimsData[ keccak256(abi.encode(msg.sender, _raffleId)) ]; require(claimData.claimed == false, "already refunded"); raffle.amountRaised = raffle.amountRaised - claimData.amountSpentInWeis; claimData.claimed = true; (bool sent, ) = msg.sender.call{value: claimData.amountSpentInWeis}(""); require(sent, "Fail send refund"); emit Refund(_raffleId, claimData.amountSpentInWeis, msg.sender); } /// @param _raffleId Id of the raffle /// @dev after 30 days after cancelling passes, the operator can transfer to /// destinationWallet the remaining funds function transferRemainingFunds(uint256 _raffleId) external nonReentrant onlyRole(OPERATOR_ROLE) { RaffleStruct storage raffle = raffles[_raffleId]; require(raffle.status == STATUS.CANCEL_REQUESTED, "Wrong status"); require( block.timestamp > raffle.cancellingDate + 30 days, "claim too soon" ); raffle.status = STATUS.CANCELLED; (bool sent, ) = destinationWallet.call{value: raffle.amountRaised}(""); require(sent, "Fail send Eth to MW"); emit RemainingFundsTransferred(_raffleId, raffle.amountRaised); raffle.amountRaised = 0; } /// @param _raffleId Id of the raffle /// @return array of entries bougth of that particular raffle function getEntriesBought(uint256 _raffleId) external view returns (EntriesBought[] memory) { return entriesList[_raffleId]; } /// @param _raffleId Id of the raffle /// @param _player wallet of the player /// @return Claims data of the player on that raffle function getClaimData(uint256 _raffleId, address _player) external view returns (ClaimStruct memory) { return claimsData[keccak256(abi.encode(_player, _raffleId))]; } /// @dev for different reasons player entries should be void /// this has a cost in gas, but this makes cheaper in gas the callback from chainlink /// This method has to be called for every raffle of the blacklisted player /// @param _raffleId Id of the raffle /// @param entriesToCancel array that contains the index of the entries to cancel. 0 based /// @param _player player who owns the entry to be voided function cancelEntry( uint256 _raffleId, uint256[] calldata entriesToCancel, address _player ) external onlyRole(OPERATOR_ROLE) { uint256 totalEntriesBoughtCancelled = 0; for (uint256 i = 0; i < entriesToCancel.length; i++) { EntriesBought storage entry = entriesList[_raffleId][ entriesToCancel[i] ]; require(entry.player == _player, "Entry did not belong to player"); entry.player = address(0); uint256 previousTotalEntriesLength; if (entriesToCancel[i] == 0) previousTotalEntriesLength = 0; else previousTotalEntriesLength = entriesList[_raffleId][ entriesToCancel[i]-1].currentEntriesLength; totalEntriesBoughtCancelled += entry.currentEntriesLength - previousTotalEntriesLength; } emit EntryCancelled(_raffleId, totalEntriesBoughtCancelled, _player); } // Requested by Valerio Di Napoli. /// @param _raffleId id of the raffle /// @param _amountOfEntries amount of entries. Must be lower than maxEntriesPerUser /// @param _player The address of the player /// @notice Called by other contract created by Valerio, that minted an NFT and after that call this method /// @dev add entries but they are free so no payable function createFreeEntriesFromExternalContract( uint256 _raffleId, uint256 _amountOfEntries, address _player ) external onlyRole(MINTERCONTRACT_ROLE) nonReentrant { // if can buy run this code. bytes32 hash = keccak256(abi.encode(_player, _raffleId)); RaffleStruct storage raffle = raffles[_raffleId]; require( raffle.entryType == ENTRY_TYPE.ONLY_EXTERNAL_CONTRACT || raffle.entryType == ENTRY_TYPE.MIXED, "Entry type not allowed" ); EntriesBought memory entryBought = EntriesBought({ player: _player, currentEntriesLength: raffle.entriesLength + _amountOfEntries }); entriesList[_raffleId].push(entryBought); // update the field entriesLength. raffle.entriesLength += _amountOfEntries; //update claim data claimsData[hash].numEntriesPerUser += _amountOfEntries; address[] memory players = new address[](1); players[0] = _player; emit FreeEntry( _raffleId, players, _amountOfEntries, raffle.entriesLength ); } function playerIsBlacklisted(address _player) external view returns (bool) { return blackListManager.isBlackListed(_player); } function raffleNotInAcceptedState(uint256 _raffleId) external view returns (bool) { RaffleStruct memory raffle = raffles[_raffleId]; return (raffle.status != STATUS.ACCEPTED); } function playerIsSeller(address _player, uint256 _raffleId) external view returns (bool) { RaffleStruct memory raffle = raffles[_raffleId]; return (raffle.seller == _player); } function playerReachedMaxEntries( address _player, uint256 _raffleId, uint256 _amountOfEntries ) external view returns (bool) { RaffleStruct memory raffle = raffles[_raffleId]; bytes32 hash = keccak256(abi.encode(_player, _raffleId)); // check there are enough entries left for this particular user return (claimsData[hash].numEntriesPerUser + _amountOfEntries > raffle.maxEntries); } /* Requested by Valerio Di Napoli. @param _player The address of the player @param _raffleId id of the raffle @param _colection Address of the required collection, if any @param _tokenIdUsed Id of the token of the required collection the player says he has and want to use in the raffle @returns bool if the player can buy or not, and string with the cause of the rejection. "" if can buy @notice Method that returns if the user can or cannot buy entries because the player owns an nft in the case or required collections. */ function playerHasRequiredNFTs( address _player, uint256 _raffleId, address _collection, uint256 _tokenIdUsed ) external view returns (bool canBuy, string memory cause) { RaffleStruct memory raffle = raffles[_raffleId]; // if the raffle requires an nft if (raffle.collectionWhitelist.length > 0) { bool hasRequiredCollection = false; for (uint256 i = 0; i < raffle.collectionWhitelist.length; i++) { if (raffle.collectionWhitelist[i] == _collection) { hasRequiredCollection = true; break; } } if (hasRequiredCollection == false) return (false, "Not in required collection"); IERC721 requiredNFT = IERC721(_collection); if (requiredNFT.ownerOf(_tokenIdUsed) != _player) return (false, "Not the owner of tokenId"); bytes32 hashRequiredNFT = keccak256( abi.encode(_collection, _raffleId, _tokenIdUsed) ); // check the tokenId has not been using yet in the raffle, to avoid abuse if (requiredNFTWallets[hashRequiredNFT] != _player) return (false, "tokenId used"); } return (true, ""); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.4; import "@openzeppelin/contracts/access/AccessControl.sol"; /// @title Blacklist manager /// @author Luis Pando /// @notice Manages the players that are blacklisted /// @dev A player is blacklisted for all the raffles at once. contract BlackListManager is AccessControl { bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR"); struct BlackListStruct { bool blacklisted; // is blacklisted the user uint256 dateBlacklisted; // when was blacklisted for the first time } // map with the wallet of the player as key mapping(address => BlackListStruct) public blackList; constructor() { _setupRole(OPERATOR_ROLE, msg.sender); _setupRole(DEFAULT_ADMIN_ROLE, msg.sender); } /// @notice Add a player to the blacklist. The blacklist is common for all the raffles /// @dev the user could be added and removed from the blacklist several times, but the /// field dateBlacklisted will contain the date of when the user was added, even if was removed /// @param _player User that has suspicious behaviour and that will be blacklisted function addToBlackList(address _player) external onlyRole(OPERATOR_ROLE) { BlackListStruct memory blElement = BlackListStruct({ blacklisted: true, dateBlacklisted: block.timestamp }); blackList[_player] = blElement; } /// @notice remove a player from the blacklist /// @param _player that will be removed from the blacklist and will be able to buy entries again function removeFromBlackList(address _player) external onlyRole(OPERATOR_ROLE) { blackList[_player].blacklisted = false; } /// @notice returns if a player is in the blacklist /// @param _player User to check if blacklisted or not /// @return true if the user wallet is in the blacklist. False otherwise function isBlackListed(address _player) external view returns (bool) { return blackList[_player].blacklisted; } /// @notice returns the date (if any) when the user was blacklisted for first time /// @dev The returned value will exists even if the user was removed from the blacklist /// Do not use it without calling isBlacklisted first /// @param _player User to return the date when blacklisted /// @return a number with the epoch of when the player was blacklisted. 0 if never blacklisted function getBlackListedDate(address _player) external view returns (uint256) { return blackList[_player].dateBlacklisted; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv( uint256 x, uint256 y, uint256 denominator, Rounding rounding ) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. It the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. // We also know that `k`, the position of the most significant bit, is such that `msb(a) = 2**k`. // This gives `2**k < a <= 2**(k+1)` → `2**(k/2) <= sqrt(a) < 2 ** (k/2+1)`. // Using an algorithm similar to the msb conmputation, we are able to compute `result = 2**(k/2)` which is a // good first aproximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1; uint256 x = a; if (x >> 128 > 0) { x >>= 128; result <<= 64; } if (x >> 64 > 0) { x >>= 64; result <<= 32; } if (x >> 32 > 0) { x >>= 32; result <<= 16; } if (x >> 16 > 0) { x >>= 16; result <<= 8; } if (x >> 8 > 0) { x >>= 8; result <<= 4; } if (x >> 4 > 0) { x >>= 4; result <<= 2; } if (x >> 2 > 0) { result <<= 1; } // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { uint256 result = sqrt(a); if (rounding == Rounding.Up && result * result < a) { result += 1; } return result; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol) pragma solidity ^0.8.0; /** * @dev String operations. */ library Strings { bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { // Inspired by OraclizeAPI's implementation - MIT licence // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol if (value == 0) { return "0"; } uint256 temp = value; uint256 digits; while (temp != 0) { digits++; temp /= 10; } bytes memory buffer = new bytes(digits); while (value != 0) { digits -= 1; buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); value /= 10; } return string(buffer); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { if (value == 0) { return "0x00"; } uint256 temp = value; uint256 length = 0; while (temp != 0) { length++; temp >>= 8; } return toHexString(value, length); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _HEX_SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor() { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) pragma solidity ^0.8.0; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControl { /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. * * _Available since v3.1._ */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {AccessControl-_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (access/AccessControl.sol) pragma solidity ^0.8.0; import "./IAccessControl.sol"; import "../utils/Context.sol"; import "../utils/Strings.sol"; import "../utils/introspection/ERC165.sol"; /** * @dev Contract module that allows children to implement role-based access * control mechanisms. This is a lightweight version that doesn't allow enumerating role * members except through off-chain means by accessing the contract event logs. Some * applications may benefit from on-chain enumerability, for those cases see * {AccessControlEnumerable}. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ``` * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ``` * function foo() public { * require(hasRole(MY_ROLE, msg.sender)); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. * * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to * grant and revoke this role. Extra precautions should be taken to secure * accounts that have been granted it. */ abstract contract AccessControl is Context, IAccessControl, ERC165 { struct RoleData { mapping(address => bool) members; bytes32 adminRole; } mapping(bytes32 => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Modifier that checks that an account has a specific role. Reverts * with a standardized message including the required role. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ * * _Available since v4.1._ */ modifier onlyRole(bytes32 role) { _checkRole(role); _; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view virtual override returns (bool) { return _roles[role].members[account]; } /** * @dev Revert with a standard message if `_msgSender()` is missing `role`. * Overriding this function changes the behavior of the {onlyRole} modifier. * * Format of the revert message is described in {_checkRole}. * * _Available since v4.6._ */ function _checkRole(bytes32 role) internal view virtual { _checkRole(role, _msgSender()); } /** * @dev Revert with a standard message if `account` is missing `role`. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ */ function _checkRole(bytes32 role, address account) internal view virtual { if (!hasRole(role, account)) { revert( string( abi.encodePacked( "AccessControl: account ", Strings.toHexString(uint160(account), 20), " is missing role ", Strings.toHexString(uint256(role), 32) ) ) ); } } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) { return _roles[role].adminRole; } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleGranted} event. */ function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _grantRole(role, account); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleRevoked} event. */ function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _revokeRole(role, account); } /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been revoked `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. * * May emit a {RoleRevoked} event. */ function renounceRole(bytes32 role, address account) public virtual override { require(account == _msgSender(), "AccessControl: can only renounce roles for self"); _revokeRole(role, account); } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. Note that unlike {grantRole}, this function doesn't perform any * checks on the calling account. * * May emit a {RoleGranted} event. * * [WARNING] * ==== * This function should only be called from the constructor when setting * up the initial roles for the system. * * Using this function in any other way is effectively circumventing the admin * system imposed by {AccessControl}. * ==== * * NOTE: This function is deprecated in favor of {_grantRole}. */ function _setupRole(bytes32 role, address account) internal virtual { _grantRole(role, account); } /** * @dev Sets `adminRole` as ``role``'s admin role. * * Emits a {RoleAdminChanged} event. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { bytes32 previousAdminRole = getRoleAdmin(role); _roles[role].adminRole = adminRole; emit RoleAdminChanged(role, previousAdminRole, adminRole); } /** * @dev Grants `role` to `account`. * * Internal function without access restriction. * * May emit a {RoleGranted} event. */ function _grantRole(bytes32 role, address account) internal virtual { if (!hasRole(role, account)) { _roles[role].members[account] = true; emit RoleGranted(role, account, _msgSender()); } } /** * @dev Revokes `role` from `account`. * * Internal function without access restriction. * * May emit a {RoleRevoked} event. */ function _revokeRole(bytes32 role, address account) internal virtual { if (hasRole(role, account)) { _roles[role].members[account] = false; emit RoleRevoked(role, account, _msgSender()); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface LinkTokenInterface { function allowance(address owner, address spender) external view returns (uint256 remaining); function approve(address spender, uint256 value) external returns (bool success); function balanceOf(address owner) external view returns (uint256 balance); function decimals() external view returns (uint8 decimalPlaces); function decreaseApproval(address spender, uint256 addedValue) external returns (bool success); function increaseApproval(address spender, uint256 subtractedValue) external; function name() external view returns (string memory tokenName); function symbol() external view returns (string memory tokenSymbol); function totalSupply() external view returns (uint256 totalTokensIssued); function transfer(address to, uint256 value) external returns (bool success); function transferAndCall( address to, uint256 value, bytes calldata data ) external returns (bool success); function transferFrom( address from, address to, uint256 value ) external returns (bool success); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract VRFRequestIDBase { /** * @notice returns the seed which is actually input to the VRF coordinator * * @dev To prevent repetition of VRF output due to repetition of the * @dev user-supplied seed, that seed is combined in a hash with the * @dev user-specific nonce, and the address of the consuming contract. The * @dev risk of repetition is mostly mitigated by inclusion of a blockhash in * @dev the final seed, but the nonce does protect against repetition in * @dev requests which are included in a single block. * * @param _userSeed VRF seed input provided by user * @param _requester Address of the requesting contract * @param _nonce User-specific nonce at the time of the request */ function makeVRFInputSeed( bytes32 _keyHash, uint256 _userSeed, address _requester, uint256 _nonce ) internal pure returns (uint256) { return uint256(keccak256(abi.encode(_keyHash, _userSeed, _requester, _nonce))); } /** * @notice Returns the id for this request * @param _keyHash The serviceAgreement ID to be used for this request * @param _vRFInputSeed The seed to be passed directly to the VRF * @return The id for this request * * @dev Note that _vRFInputSeed is not the seed passed by the consuming * @dev contract, but the one generated by makeVRFInputSeed */ function makeRequestId(bytes32 _keyHash, uint256 _vRFInputSeed) internal pure returns (bytes32) { return keccak256(abi.encodePacked(_keyHash, _vRFInputSeed)); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./interfaces/LinkTokenInterface.sol"; import "./VRFRequestIDBase.sol"; /** **************************************************************************** * @notice Interface for contracts using VRF randomness * ***************************************************************************** * @dev PURPOSE * * @dev Reggie the Random Oracle (not his real job) wants to provide randomness * @dev to Vera the verifier in such a way that Vera can be sure he's not * @dev making his output up to suit himself. Reggie provides Vera a public key * @dev to which he knows the secret key. Each time Vera provides a seed to * @dev Reggie, he gives back a value which is computed completely * @dev deterministically from the seed and the secret key. * * @dev Reggie provides a proof by which Vera can verify that the output was * @dev correctly computed once Reggie tells it to her, but without that proof, * @dev the output is indistinguishable to her from a uniform random sample * @dev from the output space. * * @dev The purpose of this contract is to make it easy for unrelated contracts * @dev to talk to Vera the verifier about the work Reggie is doing, to provide * @dev simple access to a verifiable source of randomness. * ***************************************************************************** * @dev USAGE * * @dev Calling contracts must inherit from VRFConsumerBase, and can * @dev initialize VRFConsumerBase's attributes in their constructor as * @dev shown: * * @dev contract VRFConsumer { * @dev constructor(<other arguments>, address _vrfCoordinator, address _link) * @dev VRFConsumerBase(_vrfCoordinator, _link) public { * @dev <initialization with other arguments goes here> * @dev } * @dev } * * @dev The oracle will have given you an ID for the VRF keypair they have * @dev committed to (let's call it keyHash), and have told you the minimum LINK * @dev price for VRF service. Make sure your contract has sufficient LINK, and * @dev call requestRandomness(keyHash, fee, seed), where seed is the input you * @dev want to generate randomness from. * * @dev Once the VRFCoordinator has received and validated the oracle's response * @dev to your request, it will call your contract's fulfillRandomness method. * * @dev The randomness argument to fulfillRandomness is the actual random value * @dev generated from your seed. * * @dev The requestId argument is generated from the keyHash and the seed by * @dev makeRequestId(keyHash, seed). If your contract could have concurrent * @dev requests open, you can use the requestId to track which seed is * @dev associated with which randomness. See VRFRequestIDBase.sol for more * @dev details. (See "SECURITY CONSIDERATIONS" for principles to keep in mind, * @dev if your contract could have multiple requests in flight simultaneously.) * * @dev Colliding `requestId`s are cryptographically impossible as long as seeds * @dev differ. (Which is critical to making unpredictable randomness! See the * @dev next section.) * * ***************************************************************************** * @dev SECURITY CONSIDERATIONS * * @dev A method with the ability to call your fulfillRandomness method directly * @dev could spoof a VRF response with any random value, so it's critical that * @dev it cannot be directly called by anything other than this base contract * @dev (specifically, by the VRFConsumerBase.rawFulfillRandomness method). * * @dev For your users to trust that your contract's random behavior is free * @dev from malicious interference, it's best if you can write it so that all * @dev behaviors implied by a VRF response are executed *during* your * @dev fulfillRandomness method. If your contract must store the response (or * @dev anything derived from it) and use it later, you must ensure that any * @dev user-significant behavior which depends on that stored value cannot be * @dev manipulated by a subsequent VRF request. * * @dev Similarly, both miners and the VRF oracle itself have some influence * @dev over the order in which VRF responses appear on the blockchain, so if * @dev your contract could have multiple VRF requests in flight simultaneously, * @dev you must ensure that the order in which the VRF responses arrive cannot * @dev be used to manipulate your contract's user-significant behavior. * * @dev Since the ultimate input to the VRF is mixed with the block hash of the * @dev block in which the request is made, user-provided seeds have no impact * @dev on its economic security properties. They are only included for API * @dev compatability with previous versions of this contract. * * @dev Since the block hash of the block which contains the requestRandomness * @dev call is mixed into the input to the VRF *last*, a sufficiently powerful * @dev miner could, in principle, fork the blockchain to evict the block * @dev containing the request, forcing the request to be included in a * @dev different block with a different hash, and therefore a different input * @dev to the VRF. However, such an attack would incur a substantial economic * @dev cost. This cost scales with the number of blocks the VRF oracle waits * @dev until it calls responds to a request. */ abstract contract VRFConsumerBase is VRFRequestIDBase { /** * @notice fulfillRandomness handles the VRF response. Your contract must * @notice implement it. See "SECURITY CONSIDERATIONS" above for important * @notice principles to keep in mind when implementing your fulfillRandomness * @notice method. * * @dev VRFConsumerBase expects its subcontracts to have a method with this * @dev signature, and will call it once it has verified the proof * @dev associated with the randomness. (It is triggered via a call to * @dev rawFulfillRandomness, below.) * * @param requestId The Id initially returned by requestRandomness * @param randomness the VRF output */ function fulfillRandomness(bytes32 requestId, uint256 randomness) internal virtual; /** * @dev In order to keep backwards compatibility we have kept the user * seed field around. We remove the use of it because given that the blockhash * enters later, it overrides whatever randomness the used seed provides. * Given that it adds no security, and can easily lead to misunderstandings, * we have removed it from usage and can now provide a simpler API. */ uint256 private constant USER_SEED_PLACEHOLDER = 0; /** * @notice requestRandomness initiates a request for VRF output given _seed * * @dev The fulfillRandomness method receives the output, once it's provided * @dev by the Oracle, and verified by the vrfCoordinator. * * @dev The _keyHash must already be registered with the VRFCoordinator, and * @dev the _fee must exceed the fee specified during registration of the * @dev _keyHash. * * @dev The _seed parameter is vestigial, and is kept only for API * @dev compatibility with older versions. It can't *hurt* to mix in some of * @dev your own randomness, here, but it's not necessary because the VRF * @dev oracle will mix the hash of the block containing your request into the * @dev VRF seed it ultimately uses. * * @param _keyHash ID of public key against which randomness is generated * @param _fee The amount of LINK to send with the request * * @return requestId unique ID for this request * * @dev The returned requestId can be used to distinguish responses to * @dev concurrent requests. It is passed as the first argument to * @dev fulfillRandomness. */ function requestRandomness(bytes32 _keyHash, uint256 _fee) internal returns (bytes32 requestId) { LINK.transferAndCall(vrfCoordinator, _fee, abi.encode(_keyHash, USER_SEED_PLACEHOLDER)); // This is the seed passed to VRFCoordinator. The oracle will mix this with // the hash of the block containing this request to obtain the seed/input // which is finally passed to the VRF cryptographic machinery. uint256 vRFSeed = makeVRFInputSeed(_keyHash, USER_SEED_PLACEHOLDER, address(this), nonces[_keyHash]); // nonces[_keyHash] must stay in sync with // VRFCoordinator.nonces[_keyHash][this], which was incremented by the above // successful LINK.transferAndCall (in VRFCoordinator.randomnessRequest). // This provides protection against the user repeating their input seed, // which would result in a predictable/duplicate output, if multiple such // requests appeared in the same block. nonces[_keyHash] = nonces[_keyHash] + 1; return makeRequestId(_keyHash, vRFSeed); } LinkTokenInterface internal immutable LINK; address private immutable vrfCoordinator; // Nonces for each VRF key from which randomness has been requested. // // Must stay in sync with VRFCoordinator[_keyHash][this] mapping(bytes32 => uint256) /* keyHash */ /* nonce */ private nonces; /** * @param _vrfCoordinator address of VRFCoordinator contract * @param _link address of LINK token contract * * @dev https://docs.chain.link/docs/link-token-contracts */ constructor(address _vrfCoordinator, address _link) { vrfCoordinator = _vrfCoordinator; LINK = LinkTokenInterface(_link); } // rawFulfillRandomness is called by VRFCoordinator when it receives a valid VRF // proof. rawFulfillRandomness then calls fulfillRandomness, after validating // the origin of the call function rawFulfillRandomness(bytes32 requestId, uint256 randomness) external { require(msg.sender == vrfCoordinator, "Only VRFCoordinator can fulfill"); fulfillRandomness(requestId, randomness); } }
{ "remappings": [], "optimizer": { "enabled": true, "runs": 200 }, "evmVersion": "istanbul", "libraries": {}, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_blacklistManager","type":"address"},{"internalType":"address","name":"_vrfCoordinator","type":"address"},{"internalType":"address","name":"_linkToken","type":"address"},{"internalType":"bytes32","name":"_keyHash","type":"bytes32"},{"internalType":"bool","name":"_mainetFee","type":"bool"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountRaised","type":"uint256"}],"name":"EarlyCashoutTriggered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfEntriesCanceled","type":"uint256"},{"indexed":false,"internalType":"address","name":"player","type":"address"}],"name":"EntryCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":true,"internalType":"address","name":"buyer","type":"address"},{"indexed":false,"internalType":"uint256","name":"currentSize","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"priceStructureId","type":"uint256"}],"name":"EntrySold","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountTransferred","type":"uint256"}],"name":"FeeTransferredToPlatform","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":false,"internalType":"address[]","name":"buyer","type":"address[]"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"currentSize","type":"uint256"}],"name":"FreeEntry","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountRaised","type":"uint256"}],"name":"RaffleCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"prizeAmount","type":"uint256"}],"name":"RaffleCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":true,"internalType":"address","name":"winner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountRaised","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"randomNumber","type":"uint256"}],"name":"RaffleEnded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":true,"internalType":"address","name":"seller","type":"address"}],"name":"RaffleStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"idFromMetawin","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"randomNumber","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"normalizedRandomNumber","type":"uint256"}],"name":"RandomNumberCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountInWeis","type":"uint256"},{"indexed":true,"internalType":"address","name":"player","type":"address"}],"name":"Refund","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountInWeis","type":"uint256"}],"name":"RemainingFundsTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountRaised","type":"uint256"}],"name":"SetWinnerTriggered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newStatus","type":"uint256"}],"name":"StatusChangedInEmergency","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINTERCONTRACT_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OPERATOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_raffleId","type":"uint256"},{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"address","name":"_collection","type":"address"},{"internalType":"uint256","name":"_tokenIdUsed","type":"uint256"}],"name":"buyEntry","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_raffleId","type":"uint256"},{"internalType":"uint256[]","name":"entriesToCancel","type":"uint256[]"},{"internalType":"address","name":"_player","type":"address"}],"name":"cancelEntry","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_raffleId","type":"uint256"}],"name":"cancelRaffle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"chainlinkRaffleInfo","outputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"size","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_raffleId","type":"uint256"}],"name":"claimRefund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"claimsData","outputs":[{"internalType":"uint256","name":"numEntriesPerUser","type":"uint256"},{"internalType":"uint256","name":"amountSpentInWeis","type":"uint256"},{"internalType":"bool","name":"claimed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_raffleId","type":"uint256"},{"internalType":"uint256","name":"_amountOfEntries","type":"uint256"},{"internalType":"address","name":"_player","type":"address"}],"name":"createFreeEntriesFromExternalContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_desiredFundsInWeis","type":"uint256"},{"internalType":"uint256","name":"_maxEntriesPerUser","type":"uint256"},{"internalType":"uint256","name":"_amountOfETH","type":"uint256"},{"internalType":"uint256","name":"_minimumFundsInWeis","type":"uint256"},{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"numEntries","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"}],"internalType":"struct CompetitionETHAsPrize.PriceStructure[]","name":"_prices","type":"tuple[]"},{"internalType":"uint256","name":"_commissionInBasicPoints","type":"uint256"},{"internalType":"address[]","name":"_collectionWhitelist","type":"address[]"},{"internalType":"enum CompetitionETHAsPrize.ENTRY_TYPE","name":"_entryType","type":"uint8"}],"name":"createRaffle","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"destinationWallet","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_raffleId","type":"uint256"}],"name":"earlyCashOut","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"entriesList","outputs":[{"internalType":"uint256","name":"currentEntriesLength","type":"uint256"},{"internalType":"address","name":"player","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"fundingList","outputs":[{"internalType":"uint256","name":"minimumFundsInWeis","type":"uint256"},{"internalType":"uint256","name":"desiredFundsInWeis","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_raffleId","type":"uint256"},{"internalType":"address","name":"_player","type":"address"}],"name":"getClaimData","outputs":[{"components":[{"internalType":"uint256","name":"numEntriesPerUser","type":"uint256"},{"internalType":"uint256","name":"amountSpentInWeis","type":"uint256"},{"internalType":"bool","name":"claimed","type":"bool"}],"internalType":"struct CompetitionETHAsPrize.ClaimStruct","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_raffleId","type":"uint256"}],"name":"getEntriesBought","outputs":[{"components":[{"internalType":"uint256","name":"currentEntriesLength","type":"uint256"},{"internalType":"address","name":"player","type":"address"}],"internalType":"struct CompetitionETHAsPrize.EntriesBought[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_raffleId","type":"uint256"},{"internalType":"uint256","name":"_normalizedRandomNumber","type":"uint256"}],"name":"getWinnerAddressFromRandom","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_raffleId","type":"uint256"},{"internalType":"address[]","name":"_freePlayers","type":"address[]"}],"name":"giveBatchEntriesForFree","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_player","type":"address"},{"internalType":"uint256","name":"_raffleId","type":"uint256"},{"internalType":"address","name":"_collection","type":"address"},{"internalType":"uint256","name":"_tokenIdUsed","type":"uint256"}],"name":"playerHasRequiredNFTs","outputs":[{"internalType":"bool","name":"canBuy","type":"bool"},{"internalType":"string","name":"cause","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_player","type":"address"}],"name":"playerIsBlacklisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_player","type":"address"},{"internalType":"uint256","name":"_raffleId","type":"uint256"}],"name":"playerIsSeller","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_player","type":"address"},{"internalType":"uint256","name":"_raffleId","type":"uint256"},{"internalType":"uint256","name":"_amountOfEntries","type":"uint256"}],"name":"playerReachedMaxEntries","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"prices","outputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"numEntries","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_raffleId","type":"uint256"}],"name":"raffleNotInAcceptedState","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"raffles","outputs":[{"internalType":"enum CompetitionETHAsPrize.STATUS","name":"status","type":"uint8"},{"internalType":"uint256","name":"maxEntries","type":"uint256"},{"internalType":"uint256","name":"amountOfETH","type":"uint256"},{"internalType":"address","name":"winner","type":"address"},{"internalType":"uint256","name":"randomNumber","type":"uint256"},{"internalType":"uint256","name":"amountRaised","type":"uint256"},{"internalType":"address","name":"seller","type":"address"},{"internalType":"uint256","name":"platformPercentage","type":"uint256"},{"internalType":"uint256","name":"entriesLength","type":"uint256"},{"internalType":"uint256","name":"cancellingDate","type":"uint256"},{"internalType":"enum CompetitionETHAsPrize.ENTRY_TYPE","name":"entryType","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"requestId","type":"bytes32"},{"internalType":"uint256","name":"randomness","type":"uint256"}],"name":"rawFulfillRandomness","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"requests","outputs":[{"internalType":"uint256","name":"randomNumber","type":"uint256"},{"internalType":"uint256","name":"nomalizedRandomNumber","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"requiredNFTWallets","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"_newAddress","type":"address"}],"name":"setDestinationAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_raffleId","type":"uint256"}],"name":"setWinner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_raffleId","type":"uint256"}],"name":"stakeETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_raffleId","type":"uint256"}],"name":"transferRemainingFunds","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60c0604052600d80546001600160a01b03191673eda703919a528481f4f11423a728300dcabf441f1790553480156200003757600080fd5b50604051620052d3380380620052d38339810160408190526200005a91620001ee565b600180556001600160601b0319606085811b821660a05284901b16608052620000b87f523a704056dcd17bcf83bed8b68c59416dac1119be77755efe3bde0a64e46e0c7313503b622abc0bd30a7e9687057df6e8c42fb92862000121565b620000c560003362000121565b600382905560018115151415620000e857671bc16d674ec80000600455620000f5565b67016345785d8a00006004555b5050600e80546001600160a01b0319166001600160a01b039490941693909317909255506200025b9050565b6200012d828262000131565b5050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff166200012d576000828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556200018d3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b80516001600160a01b0381168114620001e957600080fd5b919050565b600080600080600060a0868803121562000206578081fd5b6200021186620001d1565b94506200022160208701620001d1565b93506200023160408701620001d1565b925060608601519150608086015180151581146200024d578182fd5b809150509295509295909350565b60805160601c60a05160601c61503e6200029560003960008181612d480152614038015260008181613ae10152614009015261503e6000f3fe6080604052600436106102305760003560e01c80635b7baf641161012e578063a217fddf116100ab578063d649214c1161006f578063d649214c146107c7578063e2a6f547146107e7578063eb99038c14610822578063f369145514610842578063f5b541a61461086257600080fd5b8063a217fddf146106e8578063babdf60b146106fd578063baf029051461072b578063bce8340614610787578063d547741f146107a757600080fd5b80637fa4cacb116100f25780637fa4cacb1461063457806381d12c58146106545780638752bd9d1461068857806391d14854146106a857806394985ddd146106c857600080fd5b80635b7baf64146105765780635d4bc0ce146105965780635fba3171146105cd5780636ecc20da146105ed5780637c903fc01461060057600080fd5b80632a596800116101bc57806336734e341161018057806336734e34146104bf5780633ddf078f146104df5780634239a50c146104f257806352c8c6d71461051257806353b7a59b1461055657600080fd5b80632a596800146103fe5780632f2ff15d14610432578063317f30591461045257806336568abe14610472578063365e36581461049257600080fd5b80630df71602116102035780630df71602146103105780631a0187f5146103325780631e6cd395146103805780631fe96857146103a0578063248a9ca3146103c057600080fd5b8063013805c51461023557806301ffc9a714610277578063039be558146102a7578063043a1c9a146102f0575b600080fd5b34801561024157600080fd5b5061025561025036600461493b565b610884565b604080519283526001600160a01b039091166020830152015b60405180910390f35b34801561028357600080fd5b5061029761029236600461495c565b6108c9565b604051901515815260200161026e565b3480156102b357600080fd5b506102db6102c23660046148f4565b6008602052600090815260409020805460019091015482565b6040805192835260208301919091520161026e565b3480156102fc57600080fd5b5061029761030b36600461482e565b610900565b34801561031c57600080fd5b5061033061032b3660046148f4565b610ac3565b005b34801561033e57600080fd5b5061036861034d3660046148f4565b600c602052600090815260409020546001600160a01b031681565b6040516001600160a01b03909116815260200161026e565b34801561038c57600080fd5b5061029761039b3660046148f4565b610cc7565b3480156103ac57600080fd5b506102976103bb3660046147f6565b610e9d565b3480156103cc57600080fd5b506103f06103db3660046148f4565b60009081526020819052604090206001015490565b60405190815260200161026e565b34801561040a57600080fd5b506102db6104193660046148f4565b6006602052600090815260409020805460019091015482565b34801561043e57600080fd5b5061033061044d36600461490c565b610f1b565b34801561045e57600080fd5b5061033061046d3660046148f4565b610f45565b34801561047e57600080fd5b5061033061048d36600461490c565b611164565b34801561049e57600080fd5b506104b26104ad3660046148f4565b6111e2565b60405161026e9190614d35565b3480156104cb57600080fd5b506103306104da36600461499c565b61126a565b6103306104ed366004614b04565b61161b565b3480156104fe57600080fd5b5061033061050d3660046148f4565b611e2b565b34801561051e57600080fd5b5061053261052d36600461490c565b611ff4565b6040805182518152602080840151908201529181015115159082015260600161026e565b34801561056257600080fd5b50600d54610368906001600160a01b031681565b34801561058257600080fd5b506103306105913660046148f4565b612089565b3480156105a257600080fd5b506105b66105b13660046148f4565b61232a565b60405161026e9b9a99989796959493929190614da8565b3480156105d957600080fd5b506103306105e83660046148f4565b6123a8565b6103306105fb3660046148f4565b61263b565b34801561060c57600080fd5b506103f07fde5ee446972f4e39ab62c03aa34b2096680a875c3fdb3eb2f947cbb93341c05881565b34801561064057600080fd5b5061033061064f3660046147f6565b61279c565b34801561066057600080fd5b506102db61066f3660046148f4565b6005602052600090815260409020805460019091015482565b34801561069457600080fd5b506103f06106a3366004614b32565b6127ca565b3480156106b457600080fd5b506102976106c336600461490c565b612d14565b3480156106d457600080fd5b506103306106e336600461493b565b612d3d565b3480156106f457600080fd5b506103f0600081565b34801561070957600080fd5b5061071d610718366004614859565b612dbf565b60405161026e929190614d8d565b34801561073757600080fd5b5061076a6107463660046148f4565b600b6020526000908152604090208054600182015460029092015490919060ff1683565b60408051938452602084019290925215159082015260600161026e565b34801561079357600080fd5b506103306107a2366004614acc565b6131b8565b3480156107b357600080fd5b506103306107c236600461490c565b61347c565b3480156107d357600080fd5b506103306107e2366004614a6f565b6134a1565b3480156107f357600080fd5b5061080761080236600461493b565b6136c3565b6040805193845260208401929092529082015260600161026e565b34801561082e57600080fd5b5061029761083d3660046148a0565b6136f9565b34801561084e57600080fd5b5061036861085d36600461493b565b61390d565b34801561086e57600080fd5b506103f0600080516020614fe983398151915281565b600960205281600052604060002081815481106108a057600080fd5b6000918252602090912060029091020180546001909101549092506001600160a01b0316905082565b60006001600160e01b03198216637965db0b60e01b14806108fa57506301ffc9a760e01b6001600160e01b03198316145b92915050565b600080600a838154811061092457634e487b7160e01b600052603260045260246000fd5b60009182526020909120604080516101808101909152600c909202018054829060ff16600681111561096657634e487b7160e01b600052602160045260246000fd5b600681111561098557634e487b7160e01b600052602160045260246000fd5b81526001820154602080830191909152600283015460408084019190915260038401546001600160a01b03908116606085015260048501546080850152600585015460a085015260068501541660c0840152600784015460e084015260088401546101008401526009840154610120840152600a84018054825181850281018501909352808352610140909401939192909190830182828015610a5157602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610a33575b5050509183525050600b82015460209091019060ff166002811115610a8657634e487b7160e01b600052602160045260246000fd5b6002811115610aa557634e487b7160e01b600052602160045260246000fd5b90525060c001516001600160a01b0385811691161491505092915050565b60026001541415610aef5760405162461bcd60e51b8152600401610ae690614e6c565b60405180910390fd5b6002600155600080516020614fe9833981519152610b0c81613ab6565b6000600a8381548110610b2f57634e487b7160e01b600052603260045260246000fd5b6000918252602080832086845260089091526040909220600c90910290910191506001825460ff166006811115610b7657634e487b7160e01b600052602160045260246000fd5b14610bbc5760405162461bcd60e51b8152602060048201526016602482015275526166666c6520696e2077726f6e672073746174757360501b6044820152606401610ae6565b805460058301541015610c0b5760405162461bcd60e51b8152602060048201526017602482015276139bdd08195b9bdd59da08199d5b991cc81c985a5cd959604a1b6044820152606401610ae6565b816005015481600101541115610c635760405162461bcd60e51b815260206004820152601860248201527f446573697265642066756e6473206e6f742072616973656400000000000000006044820152606401610ae6565b815460ff191660041782556008820154610c7e908590613ac3565b50837ff2be214756d2fbc1e781d10809ddef33000009d805be55356bb348134ce21c688360050154604051610cb591815260200190565b60405180910390a25050600180555050565b600080600a8381548110610ceb57634e487b7160e01b600052603260045260246000fd5b60009182526020909120604080516101808101909152600c909202018054829060ff166006811115610d2d57634e487b7160e01b600052602160045260246000fd5b6006811115610d4c57634e487b7160e01b600052602160045260246000fd5b81526001820154602080830191909152600283015460408084019190915260038401546001600160a01b03908116606085015260048501546080850152600585015460a085015260068501541660c0840152600784015460e084015260088401546101008401526009840154610120840152600a84018054825181850281018501909352808352610140909401939192909190830182828015610e1857602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610dfa575b5050509183525050600b82015460209091019060ff166002811115610e4d57634e487b7160e01b600052602160045260246000fd5b6002811115610e6c57634e487b7160e01b600052602160045260246000fd5b9052509050600181516006811115610e9457634e487b7160e01b600052602160045260246000fd5b14159392505050565b600e54604051630723eb0360e51b81526001600160a01b038381166004830152600092169063e47d60609060240160206040518083038186803b158015610ee357600080fd5b505afa158015610ef7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108fa91906148d4565b600082815260208190526040902060010154610f3681613ab6565b610f408383613c09565b505050565b60026001541415610f685760405162461bcd60e51b8152600401610ae690614e6c565b6002600155600080516020614fe9833981519152610f8581613ab6565b6000600a8381548110610fa857634e487b7160e01b600052603260045260246000fd5b60009182526020909120600c9091020190506006815460ff166006811115610fe057634e487b7160e01b600052602160045260246000fd5b1461101c5760405162461bcd60e51b815260206004820152600c60248201526b57726f6e672073746174757360a01b6044820152606401610ae6565b600981015461102e9062278d00614ea3565b421161106d5760405162461bcd60e51b815260206004820152600e60248201526d31b630b4b6903a37b79039b7b7b760911b6044820152606401610ae6565b805460ff19166003178155600d5460058201546040516000926001600160a01b031691908381818185875af1925050503d80600081146110c9576040519150601f19603f3d011682016040523d82523d6000602084013e6110ce565b606091505b50509050806111155760405162461bcd60e51b81526020600482015260136024820152724661696c2073656e642045746820746f204d5760681b6044820152606401610ae6565b837fcdef6558dae40f2699846eedf449462daab85b1224ad7f077569ba91aaa94925836005015460405161114b91815260200190565b60405180910390a2506000600590910155505060018055565b6001600160a01b03811633146111d45760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401610ae6565b6111de8282613c8d565b5050565b606060096000838152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b8282101561125f5760008481526020908190206040805180820190915260028502909101805482526001908101546001600160a01b0316828401529083529092019101611217565b505050509050919050565b6002600154141561128d5760405162461bcd60e51b8152600401610ae690614e6c565b6002600155600080516020614fe98339815191526112aa81613ab6565b6001600a84815481106112cd57634e487b7160e01b600052603260045260246000fd5b60009182526020909120600c909102015460ff16600681111561130057634e487b7160e01b600052602160045260246000fd5b146113495760405162461bcd60e51b8152602060048201526019602482015278149859999b19481a5cc81b9bdd081a5b881858d8d95c1d1959603a1b6044820152606401610ae6565b81516000805b8281101561152d57600085828151811061137957634e487b7160e01b600052603260045260246000fd5b60200260200101519050600a87815481106113a457634e487b7160e01b600052603260045260246000fd5b90600052602060002090600c020160010154600b6000838a6040516020016113e19291906001600160a01b03929092168252602082015260400190565b6040516020818303038152906040528051906020012081526020019081526020016000206000015460016114159190614ea3565b1161151a576000604051806040016040528084600a8b8154811061144957634e487b7160e01b600052603260045260246000fd5b90600052602060002090600c0201600801546114659190614ea3565b611470906001614ea3565b81526001600160a01b03848116602092830181905260008c8152600984526040808220805460018082018355918452868420885160029092020190815587870151910180546001600160a01b03191691909516179093558251808501929092528183018d9052825180830384018152606090920183528151918401919091208152600b909252812080549293509061150783614f4c565b91905055508361151690614f4c565b9350505b508061152581614f4c565b91505061134f565b5080600a868154811061155057634e487b7160e01b600052603260045260246000fd5b90600052602060002090600c02016008015461156c9190614ea3565b600a868154811061158d57634e487b7160e01b600052603260045260246000fd5b90600052602060002090600c020160080181905550847f4da4f5fab0816c65315b6f5d15f879f96b98661133d7b3787788f291367604fb8584600a89815481106115e757634e487b7160e01b600052603260045260246000fd5b90600052602060002090600c02016008015460405161160893929190614cdf565b60405180910390a2505060018055505050565b6002600154141561163e5760405162461bcd60e51b8152600401610ae690614e6c565b60026001819055506000600a858154811061166957634e487b7160e01b600052603260045260246000fd5b600091825260209091206006600c90920201908101549091506001600160a01b03163314156116ce5760405162461bcd60e51b815260206004820152601160248201527053656c6c65722063616e6e6f742062757960781b6044820152606401610ae6565b6002600b82015460ff1660028111156116f757634e487b7160e01b600052602160045260246000fd5b148061172957506000600b82015460ff16600281111561172757634e487b7160e01b600052602160045260246000fd5b145b61176e5760405162461bcd60e51b8152602060048201526016602482015275115b9d1c9e481d1e5c19481b9bdd08185b1b1bddd95960521b6044820152606401610ae6565b600e54604051630723eb0360e51b81523360048201526001600160a01b039091169063e47d60609060240160206040518083038186803b1580156117b157600080fd5b505afa1580156117c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117e991906148d4565b156118255760405162461bcd60e51b815260206004820152600c60248201526b426c61636b6c69737465642160a01b6044820152606401610ae6565b600a81015415611a99576000805b600a8301548110156118a257846001600160a01b031683600a01828154811061186c57634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b0316141561189057600191506118a2565b8061189a81614f4c565b915050611833565b506001811515146118f55760405162461bcd60e51b815260206004820152601a60248201527f4e6f7420696e20726571756972656420636f6c6c656374696f6e0000000000006044820152606401610ae6565b6040516331a9108f60e11b815260048101849052849033906001600160a01b03831690636352211e9060240160206040518083038186803b15801561193957600080fd5b505afa15801561194d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119719190614812565b6001600160a01b0316146119c25760405162461bcd60e51b8152602060048201526018602482015277139bdd081d1a19481bdddb995c881bd9881d1bdad95b925960421b6044820152606401610ae6565b604080516001600160a01b03871660208201529081018890526060810185905260009060800160408051601f1981840301815291815281516020928301206000818152600c9093529120549091506001600160a01b0316611a40576000818152600c6020526040902080546001600160a01b03191633179055611a95565b6000818152600c60205260409020546001600160a01b03163314611a955760405162461bcd60e51b815260206004820152600c60248201526b1d1bdad95b9259081d5cd95960a21b6044820152606401610ae6565b5050505b33611adb5760405162461bcd60e51b81526020600482015260126024820152711b5cd9cb9cd95b99195c881a5cc81b9d5b1b60721b6044820152606401610ae6565b60008411611b1a5760405162461bcd60e51b815260206004820152600c60248201526b0686f774d616e7920697320360a41b6044820152606401610ae6565b6001815460ff166006811115611b4057634e487b7160e01b600052602160045260246000fd5b14611b895760405162461bcd60e51b8152602060048201526019602482015278149859999b19481a5cc81b9bdd081a5b881858d8d95c1d1959603a1b6044820152606401610ae6565b6000611b958686613cf2565b90506000816020015111611bde5760405162461bcd60e51b815260206004820152601060248201526f1a59081b9bdd081cdd5c1c1bdc9d195960821b6044820152606401610ae6565b80604001513414611c3d5760405162461bcd60e51b8152602060048201526024808201527f6d73672e76616c7565206d75737420626520657175616c20746f2074686520706044820152637269636560e01b6064820152608401610ae6565b6040805133602082015290810187905260009060600160408051601f1981840301815291815281516020928301206001860154858401516000838152600b9095529290932054909350611c909190614ea3565b1115611cde5760405162461bcd60e51b815260206004820152601760248201527f426f7567687420746f6f206d616e7920656e74726965730000000000000000006044820152606401610ae6565b6000604051806040016040528084602001518660080154611cff9190614ea3565b81523360209182015260008a81526009825260408120805460018082018355918352838320855160029092020190815592840151920180546001600160a01b0319166001600160a01b03909316929092179091556005860180549293503492909190611d6c908490614ea3565b909155505060208301516008850154611d859190614ea3565b60088501556020808401516000848152600b90925260408220805491929091611daf908490614ea3565b90915550506000828152600b602052604081206001018054349290611dd5908490614ea3565b90915550506008840154604080519182526020820189905233918a917fd746af8dc82f9bed98cea0fe0264eb1c3d2e5f7bcc77fc5efb429c79df40788791015b60405180910390a3505060018055505050505050565b6000600a8281548110611e4e57634e487b7160e01b600052603260045260246000fd5b600091825260208083208584526008825260409384902084518086019095528054855260010154918401919091526006600c90920201908101549092506001600160a01b03163314611ed35760405162461bcd60e51b815260206004820152600e60248201526d2737ba103a34329039b2b63632b960911b6044820152606401610ae6565b6001825460ff166006811115611ef957634e487b7160e01b600052602160045260246000fd5b14611f465760405162461bcd60e51b815260206004820152601d60248201527f526166666c65206e6f7420696e206163636570746564207374617475730000006044820152606401610ae6565b805160058301541015611f955760405162461bcd60e51b8152602060048201526017602482015276139bdd08195b9bdd59da08199d5b991cc81c985a5cd959604a1b6044820152606401610ae6565b815460ff191660021782556008820154611fb0908490613ac3565b50827f66859952a354270d9bd258f064bfb08464306538d8a01f12e1b9c6be7def11058360050154604051611fe791815260200190565b60405180910390a2505050565b61201a604051806060016040528060008152602001600081526020016000151581525090565b50604080516001600160a01b039290921660208084019190915282820193909352805180830382018152606083018083528151918501919091206000908152600b9094529281902060c0830190915280548352600181015460808301526002015460ff16151560a09091015290565b600260015414156120ac5760405162461bcd60e51b8152600401610ae690614e6c565b60026001819055506000600a82815481106120d757634e487b7160e01b600052603260045260246000fd5b60009182526020909120600c9091020190506006815460ff16600681111561210f57634e487b7160e01b600052602160045260246000fd5b1461214b5760405162461bcd60e51b815260206004820152600c60248201526b77726f6e672073746174757360a01b6044820152606401610ae6565b600981015461215d9062278d00614ea3565b4211156121a15760405162461bcd60e51b815260206004820152601260248201527118db185a5b481d1a5b5948195e1c1a5c995960721b6044820152606401610ae6565b6040805133602080830191909152818301859052825180830384018152606090920183528151918101919091206000908152600b90915220600281015460ff16156122215760405162461bcd60e51b815260206004820152601060248201526f185b1c9958591e481c99599d5b99195960821b6044820152606401610ae6565b806001015482600501546122359190614eee565b600583015560028101805460ff1916600190811790915581015460405160009133918381818185875af1925050503d806000811461228f576040519150601f19603f3d011682016040523d82523d6000602084013e612294565b606091505b50509050806122d85760405162461bcd60e51b815260206004820152601060248201526f11985a5b081cd95b99081c99599d5b9960821b6044820152606401610ae6565b336001600160a01b0316847ffe438001a6dd8298a7672e341088143b150c2227f220b57280a002f5357612b7846001015460405161231891815260200190565b60405180910390a35050600180555050565b600a818154811061233a57600080fd5b60009182526020909120600c9091020180546001820154600283015460038401546004850154600586015460068701546007880154600889015460098a0154600b909a015460ff998a169b50979996986001600160a01b03968716989597949690931694919390929091168b565b600260015414156123cb5760405162461bcd60e51b8152600401610ae690614e6c565b6002600155600080516020614fe98339815191526123e881613ab6565b6000600a838154811061240b57634e487b7160e01b600052603260045260246000fd5b60009182526020909120600c9091020190506005815460ff16600681111561244357634e487b7160e01b600052602160045260246000fd5b1415801561247557506003815460ff16600681111561247257634e487b7160e01b600052602160045260246000fd5b14155b80156124a557506002815460ff1660068111156124a257634e487b7160e01b600052602160045260246000fd5b14155b80156124d557506004815460ff1660068111156124d257634e487b7160e01b600052602160045260246000fd5b14155b801561250557506006815460ff16600681111561250257634e487b7160e01b600052602160045260246000fd5b14155b6125405760405162461bcd60e51b815260206004820152600c60248201526b57726f6e672073746174757360a01b6044820152606401610ae6565b6001815460ff16600681111561256657634e487b7160e01b600052602160045260246000fd5b14156125e757600681015460028201546040516000926001600160a01b031691908381818185875af1925050503d80600081146125bf576040519150601f19603f3d011682016040523d82523d6000602084013e6125c4565b606091505b50509050806125e55760405162461bcd60e51b8152600401610ae690614e3e565b505b805460ff19166006178155426009820155600581015460405190815283907fd512a34b0f0618078770fcd85d974df1ab46a7882e8b3d45aa91764f4961aed29060200160405180910390a250506001805550565b6002600154141561265e5760405162461bcd60e51b8152600401610ae690614e6c565b60026001819055506000600a828154811061268957634e487b7160e01b600052603260045260246000fd5b600091825260208220600c909102019150815460ff1660068111156126be57634e487b7160e01b600052602160045260246000fd5b146127005760405162461bcd60e51b8152602060048201526012602482015271149859999b19481b9bdd0810d4915055115160721b6044820152606401610ae6565b348160020154146127465760405162461bcd60e51b815260206004820152601060248201526f141c9a5e99481b9bdd081cdd185ad95960821b6044820152606401610ae6565b805460ff19166001178155600681018054336001600160a01b0319909116811790915560405183907f8bb509eedfd1c4847b0a8a2b4493cf2ebb9970dc367e477cd2a8523e212dc1db90600090a3505060018055565b60006127a781613ab6565b50600d80546001600160a01b0319166001600160a01b0392909216919091179055565b6000600080516020614fe98339815191526127e481613ab6565b60008b116128265760405162461bcd60e51b815260206004820152600f60248201526e06d6178456e7472696573206973203608c1b6044820152606401610ae6565b60008a116128635760405162461bcd60e51b815260206004820152600a60248201526905072697a6520697320360b41b6044820152606401610ae6565b6113888611156128ab5760405162461bcd60e51b81526020600482015260136024820152720c6dedadad2e6e6d2dedc40e8dede40d0d2ced606b1b6044820152606401610ae6565b604080516101808101909152600090808281526020018d81526020018c815260200160006001600160a01b031681526020016000815260200160008152602001336001600160a01b03168152602001888152602001600081526020016000815260200187878080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050509082525060200185600281111561296757634e487b7160e01b600052602160045260246000fd5b9052600a8054600181810183556000929092528251600c9091027fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a801805493945084939092839160ff1916908360068111156129d357634e487b7160e01b600052602160045260246000fd5b021790555060208281015160018301556040830151600283015560608301516003830180546001600160a01b039283166001600160a01b0319918216179091556080850151600485015560a0850151600585015560c085015160068501805491909316911617905560e08301516007830155610100830151600883015561012083015160098301556101408301518051612a7392600a8501920190614713565b50610160820151600b8201805460ff19166001836002811115612aa657634e487b7160e01b600052602160045260246000fd5b0217905550505087612ae65760405162461bcd60e51b81526020600482015260096024820152684e6f2070726963657360b81b6044820152606401610ae6565b60005b88811015612c735760008a8a83818110612b1357634e487b7160e01b600052603260045260246000fd5b9050606002016020013511612b5c5760405162461bcd60e51b815260206004820152600f60248201526e06e756d456e7472696573206973203608c1b6044820152606401610ae6565b600060405180606001604052808c8c85818110612b8957634e487b7160e01b600052603260045260246000fd5b9050606002016000013581526020018c8c85818110612bb857634e487b7160e01b600052603260045260246000fd5b9050606002016020013581526020018c8c85818110612be757634e487b7160e01b600052603260045260246000fd5b90506060020160400135815250905080600760006001600a80549050612c0d9190614eee565b81526020019081526020016000208360058110612c3a57634e487b7160e01b600052603260045260246000fd5b60030201600082015181600001556020820151816001015560408201518160020155905050508080612c6b90614f4c565b915050612ae9565b5060405180604001604052808b81526020018e815250600860006001600a80549050612c9f9190614eee565b815260208082019290925260400160002082518155910151600191820155600a548c91612ccb91614eee565b6040517ff6f5afeb49bc62176d1efaa06a1753999cc29bf378f1004ea916f37f41d7638a90600090a3600a54612d0390600190614eee565b9d9c50505050505050505050505050565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612db55760405162461bcd60e51b815260206004820152601f60248201527f4f6e6c7920565246436f6f7264696e61746f722063616e2066756c66696c6c006044820152606401610ae6565b6111de8282613df7565b600060606000600a8681548110612de657634e487b7160e01b600052603260045260246000fd5b60009182526020909120604080516101808101909152600c909202018054829060ff166006811115612e2857634e487b7160e01b600052602160045260246000fd5b6006811115612e4757634e487b7160e01b600052602160045260246000fd5b81526001820154602080830191909152600283015460408084019190915260038401546001600160a01b03908116606085015260048501546080850152600585015460a085015260068501541660c0840152600784015460e084015260088401546101008401526009840154610120840152600a84018054825181850281018501909352808352610140909401939192909190830182828015612f1357602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612ef5575b5050509183525050600b82015460209091019060ff166002811115612f4857634e487b7160e01b600052602160045260246000fd5b6002811115612f6757634e487b7160e01b600052602160045260246000fd5b9052506101408101515190915015613199576000805b82610140015151811015612fec57866001600160a01b03168361014001518281518110612fba57634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b03161415612fda5760019150612fec565b80612fe481614f4c565b915050612f7d565b50806130355760006040518060400160405280601a81526020017f4e6f7420696e20726571756972656420636f6c6c656374696f6e0000000000008152509350935050506131af565b6040516331a9108f60e11b81526004810186905286906001600160a01b038a81169190831690636352211e9060240160206040518083038186803b15801561307c57600080fd5b505afa158015613090573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130b49190614812565b6001600160a01b03161461310157600060405180604001604052806018815260200177139bdd081d1a19481bdddb995c881bd9881d1bdad95b925960421b815250945094505050506131af565b604080516001600160a01b03891660208201529081018990526060810187905260009060800160408051808303601f1901815291815281516020928301206000818152600c9093529120549091506001600160a01b038b81169116146131955760006040518060400160405280600c81526020016b1d1bdad95b9259081d5cd95960a21b81525095509550505050506131af565b5050505b5050604080516020810190915260008152600191505b94509492505050565b7fde5ee446972f4e39ab62c03aa34b2096680a875c3fdb3eb2f947cbb93341c0586131e281613ab6565b600260015414156132055760405162461bcd60e51b8152600401610ae690614e6c565b6002600155604080516001600160a01b03841660208201529081018590526000906060016040516020818303038152906040528051906020012090506000600a868154811061326457634e487b7160e01b600052603260045260246000fd5b60009182526020909120600c9091020190506001600b82015460ff16600281111561329f57634e487b7160e01b600052602160045260246000fd5b14806132d157506002600b82015460ff1660028111156132cf57634e487b7160e01b600052602160045260246000fd5b145b6133165760405162461bcd60e51b8152602060048201526016602482015275115b9d1c9e481d1e5c19481b9bdd08185b1b1bddd95960521b6044820152606401610ae6565b600060405180604001604052808784600801546133339190614ea3565b81526001600160a01b0387811660209283015260008a81526009835260408120805460018082018355918352848320865160029092020190815593850151930180546001600160a01b0319169390921692909217905560088401805492935088929091906133a2908490614ea3565b90915550506000838152600b6020526040812080548892906133c5908490614ea3565b909155505060408051600180825281830190925260009160208083019080368337019050509050858160008151811061340e57634e487b7160e01b600052603260045260246000fd5b60200260200101906001600160a01b031690816001600160a01b031681525050877f4da4f5fab0816c65315b6f5d15f879f96b98661133d7b3787788f291367604fb8289866008015460405161346693929190614cdf565b60405180910390a2505060018055505050505050565b60008281526020819052604090206001015461349781613ab6565b610f408383613c8d565b600080516020614fe98339815191526134b981613ab6565b6000805b848110156136775760008781526009602052604081208787848181106134f357634e487b7160e01b600052603260045260246000fd5b905060200201358154811061351857634e487b7160e01b600052603260045260246000fd5b6000918252602090912060029091020160018101549091506001600160a01b0386811691161461358a5760405162461bcd60e51b815260206004820152601e60248201527f456e74727920646964206e6f742062656c6f6e6720746f20706c6179657200006044820152606401610ae6565b6001810180546001600160a01b031916905560008787848181106135be57634e487b7160e01b600052603260045260246000fd5b90506020020135600014156135d557506000613649565b6000898152600960205260409020600189898681811061360557634e487b7160e01b600052603260045260246000fd5b905060200201356136169190614eee565b8154811061363457634e487b7160e01b600052603260045260246000fd5b90600052602060002090600202016000015490505b8154613656908290614eee565b6136609085614ea3565b93505050808061366f90614f4c565b9150506134bd565b50604080518281526001600160a01b038516602082015287917f2cca80c1af5abb202a642a502875436822768d733462843a7c3a902b0fad99d0910160405180910390a2505050505050565b600760205281600052604060002081600581106136df57600080fd5b600302018054600182015460029092015490935090915083565b600080600a848154811061371d57634e487b7160e01b600052603260045260246000fd5b60009182526020909120604080516101808101909152600c909202018054829060ff16600681111561375f57634e487b7160e01b600052602160045260246000fd5b600681111561377e57634e487b7160e01b600052602160045260246000fd5b81526001820154602080830191909152600283015460408084019190915260038401546001600160a01b03908116606085015260048501546080850152600585015460a085015260068501541660c0840152600784015460e084015260088401546101008401526009840154610120840152600a8401805482518185028101850190935280835261014090940193919290919083018282801561384a57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161382c575b5050509183525050600b82015460209091019060ff16600281111561387f57634e487b7160e01b600052602160045260246000fd5b600281111561389e57634e487b7160e01b600052602160045260246000fd5b905250604080516001600160a01b0388166020820152908101869052909150600090606001604051602081830303815290604052805190602001209050816020015184600b6000848152602001908152602001600020600001546139029190614ea3565b119695505050505050565b600082815260096020526040812081906139279084613eb4565b6000858152600960205260408120805492935090918390811061395a57634e487b7160e01b600052603260045260246000fd5b60009182526020909120600160029092020101546001600160a01b0316905080156139885791506108fa9050565b6000825b811580156139e2575060008781526009602052604081208054839081106139c357634e487b7160e01b600052603260045260246000fd5b60009182526020909120600160029092020101546001600160a01b0316145b15613a195780613a0e57600087815260096020526040902054613a0790600190614eee565b905061398c565b613a07600182614eee565b8115613a5f5760405162461bcd60e51b8152602060048201526015602482015274105b1b081d5cd95c9cc8189b1858dadb1a5cdd1959605a1b6044820152606401610ae6565b6000878152600960205260409020805482908110613a8d57634e487b7160e01b600052603260045260246000fd5b60009182526020909120600160029092020101546001600160a01b031694506108fa9350505050565b613ac08133613fa1565b50565b600480546040516370a0823160e01b815230928101929092526000917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015613b2b57600080fd5b505afa158015613b3f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b639190614984565b1015613bc55760405162461bcd60e51b815260206004820152602b60248201527f4e6f7420656e6f756768204c494e4b202d2066696c6c20636f6e74726163742060448201526a1dda5d1a0819985d58d95d60aa1b6064820152608401610ae6565b6000613bd5600354600454614005565b6040805180820182529586526020808701958652600083815260069091522094518555925160019094019390935550919050565b613c138282612d14565b6111de576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055613c493390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b613c978282612d14565b156111de576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b613d1660405180606001604052806000815260200160008152602001600081525090565b60005b6005811015613dd057600084815260076020526040902083908260058110613d5157634e487b7160e01b600052603260045260246000fd5b60030201541415613dbe5760008481526007602052604090208160058110613d8957634e487b7160e01b600052603260045260246000fd5b6003020160405180606001604052908160008201548152602001600182015481526020016002820154815250509150506108fa565b80613dc881614f4c565b915050613d19565b50604051806060016040528060008152602001600081526020016000815250905092915050565b6000828152600660209081526040808320815180830190925280548252600101549181018290529190613e2a9084614f67565b613e35906001614ea3565b60408051808201825285815260208082018481528651600090815260058352849020835181559051600190910155855183518881529182018590529394509092917f7c40e661b8212d0c4f60ac6e6ebed99c28680c7b3ede5b82f3b0254543f62fca910160405180910390a28251613ead9083614198565b5050505050565b8154600090613ec5575060006108fa565b82546000905b80821015613f36576000613edf838361450f565b905084868281548110613f0257634e487b7160e01b600052603260045260246000fd5b9060005260206000209060020201600001541115613f2257809150613f30565b613f2d816001614ea3565b92505b50613ecb565b600082118015613f8057508385613f4e600185614eee565b81548110613f6c57634e487b7160e01b600052603260045260246000fd5b906000526020600020906002020160000154145b15613f9957613f90600183614eee565b925050506108fa565b5090506108fa565b613fab8282612d14565b6111de57613fc3816001600160a01b03166014614531565b613fce836020614531565b604051602001613fdf929190614c3a565b60408051601f198184030181529082905262461bcd60e51b8252610ae691600401614e2b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316634000aea07f000000000000000000000000000000000000000000000000000000000000000084866000604051602001614075929190918252602082015260400190565b6040516020818303038152906040526040518463ffffffff1660e01b81526004016140a293929190614caf565b602060405180830381600087803b1580156140bc57600080fd5b505af11580156140d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140f491906148d4565b50600083815260026020818152604080842054815180840189905280830186905230606082015260808082018390528351808303909101815260a090910190925281519183019190912093879052919052614150906001614ea3565b6000858152600260205260409020556141908482604080516020808201949094528082019290925280518083038201815260609092019052805191012090565b949350505050565b600260015414156141bb5760405162461bcd60e51b8152600401610ae690614e6c565b60026001819055506000600a83815481106141e657634e487b7160e01b600052603260045260246000fd5b60009182526020909120600c9091020190506002815460ff16600681111561421e57634e487b7160e01b600052602160045260246000fd5b148061424d57506004815460ff16600681111561424b57634e487b7160e01b600052602160045260246000fd5b145b6142925760405162461bcd60e51b8152602060048201526016602482015275526166666c6520696e2077726f6e672073746174757360501b6044820152606401610ae6565b600481018290556142a3838361390d565b6003820180546001600160a01b03929092166001600160a01b031990921682179055815460ff19166005178255600282015460405160009291908381818185875af1925050503d8060008114614315576040519150601f19603f3d011682016040523d82523d6000602084013e61431a565b606091505b505090508061433b5760405162461bcd60e51b8152600401610ae690614e3e565b6000612710836007015484600501546143549190614ecf565b61435e9190614ebb565b905060008184600501546143729190614eee565b60068501546040519192506000916001600160a01b039091169083908381818185875af1925050503d80600081146143c6576040519150601f19603f3d011682016040523d82523d6000602084013e6143cb565b606091505b50509050806143ec5760405162461bcd60e51b8152600401610ae690614e3e565b600d546040516000916001600160a01b03169085908381818185875af1925050503d8060008114614439576040519150601f19603f3d011682016040523d82523d6000602084013e61443e565b606091505b50509050806144875760405162461bcd60e51b81526020600482015260156024820152744661696c65642073656e642045746820746f204d5760581b6044820152606401610ae6565b877f7378e11c2b0ec7514bbf7ba369980eedcba0bca03e116dc9e7138f7748e211d6856040516144b991815260200190565b60405180910390a26003860154600587015460408051918252602082018a90526001600160a01b03909216918a917fe0b2a72a0644b093aac275024c05c7c28851a0b572557a32241d13634a0f3e089101611e15565b600061451e6002848418614ebb565b61452a90848416614ea3565b9392505050565b60606000614540836002614ecf565b61454b906002614ea3565b67ffffffffffffffff81111561457157634e487b7160e01b600052604160045260246000fd5b6040519080825280601f01601f19166020018201604052801561459b576020820181803683370190505b509050600360fc1b816000815181106145c457634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061460157634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a9053506000614625846002614ecf565b614630906001614ea3565b90505b60018111156146c4576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811061467257634e487b7160e01b600052603260045260246000fd5b1a60f81b82828151811061469657634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a90535060049490941c936146bd81614f35565b9050614633565b50831561452a5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610ae6565b828054828255906000526020600020908101928215614768579160200282015b8281111561476857825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190614733565b50614774929150614778565b5090565b5b808211156147745760008155600101614779565b803561479881614fd3565b919050565b60008083601f8401126147ae578182fd5b50813567ffffffffffffffff8111156147c5578182fd5b6020830191508360208260051b85010111156147e057600080fd5b9250929050565b80356003811061479857600080fd5b600060208284031215614807578081fd5b813561452a81614fd3565b600060208284031215614823578081fd5b815161452a81614fd3565b60008060408385031215614840578081fd5b823561484b81614fd3565b946020939093013593505050565b6000806000806080858703121561486e578182fd5b843561487981614fd3565b935060208501359250604085013561489081614fd3565b9396929550929360600135925050565b6000806000606084860312156148b4578283fd5b83356148bf81614fd3565b95602085013595506040909401359392505050565b6000602082840312156148e5578081fd5b8151801515811461452a578182fd5b600060208284031215614905578081fd5b5035919050565b6000806040838503121561491e578182fd5b82359150602083013561493081614fd3565b809150509250929050565b6000806040838503121561494d578182fd5b50508035926020909101359150565b60006020828403121561496d578081fd5b81356001600160e01b03198116811461452a578182fd5b600060208284031215614995578081fd5b5051919050565b600080604083850312156149ae578182fd5b8235915060208084013567ffffffffffffffff808211156149cd578384fd5b818601915086601f8301126149e0578384fd5b8135818111156149f2576149f2614fbd565b8060051b604051601f19603f83011681018181108582111715614a1757614a17614fbd565b604052828152858101935084860182860187018b1015614a35578788fd5b8795505b83861015614a5e57614a4a8161478d565b855260019590950194938601938601614a39565b508096505050505050509250929050565b60008060008060608587031215614a84578182fd5b84359350602085013567ffffffffffffffff811115614aa1578283fd5b614aad8782880161479d565b9094509250506040850135614ac181614fd3565b939692955090935050565b600080600060608486031215614ae0578081fd5b83359250602084013591506040840135614af981614fd3565b809150509250925092565b60008060008060808587031215614b19578182fd5b8435935060208501359250604085013561489081614fd3565b6000806000806000806000806000806101008b8d031215614b51578788fd5b8a35995060208b0135985060408b0135975060608b0135965060808b013567ffffffffffffffff80821115614b84578788fd5b818d0191508d601f830112614b97578788fd5b813581811115614ba5578889fd5b8e6020606083028501011115614bb9578889fd5b6020830198508097505060a08d0135955060c08d0135915080821115614bdd578485fd5b50614bea8d828e0161479d565b9094509250614bfd905060e08c016147e7565b90509295989b9194979a5092959850565b60008151808452614c26816020860160208601614f05565b601f01601f19169290920160200192915050565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351614c72816017850160208801614f05565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351614ca3816028840160208801614f05565b01602801949350505050565b60018060a01b0384168152826020820152606060408201526000614cd66060830184614c0e565b95945050505050565b606080825284519082018190526000906020906080840190828801845b82811015614d215781516001600160a01b031684529284019290840190600101614cfc565b505050908301949094525060400152919050565b602080825282518282018190526000919060409081850190868401855b82811015614d80578151805185528601516001600160a01b0316868501529284019290850190600101614d52565b5091979650505050505050565b82151581526040602082015260006141906040830184614c0e565b610160810160078d10614dbd57614dbd614fa7565b8c82528b60208301528a604083015260018060a01b03808b1660608401528960808401528860a084015280881660c0840152508560e0830152846101008301528361012083015260038310614e1457614e14614fa7565b826101408301529c9b505050505050505050505050565b60208152600061452a6020830184614c0e565b6020808252601490820152732330b4b632b2103a379039b2b7321022ba3432b960611b604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60008219821115614eb657614eb6614f7b565b500190565b600082614eca57614eca614f91565b500490565b6000816000190483118215151615614ee957614ee9614f7b565b500290565b600082821015614f0057614f00614f7b565b500390565b60005b83811015614f20578181015183820152602001614f08565b83811115614f2f576000848401525b50505050565b600081614f4457614f44614f7b565b506000190190565b6000600019821415614f6057614f60614f7b565b5060010190565b600082614f7657614f76614f91565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114613ac057600080fdfe523a704056dcd17bcf83bed8b68c59416dac1119be77755efe3bde0a64e46e0ca26469706673582212209e8d2fbf52ca937a29e8344115855b614692a912217b2a69bae5b96d55b7520f64736f6c634300080400330000000000000000000000003be4bef162cd158887cfdca89a34fae107ab2c74000000000000000000000000f0d54349addcf704f77ae15b96510dea15cb7952000000000000000000000000514910771af9ca656af840dff83e8264ecf986caaa77729d3466ca35ae8d28b3bbac7cc36a5031efdc430821c02bc31a238af4450000000000000000000000000000000000000000000000000000000000000001
Deployed Bytecode
0x6080604052600436106102305760003560e01c80635b7baf641161012e578063a217fddf116100ab578063d649214c1161006f578063d649214c146107c7578063e2a6f547146107e7578063eb99038c14610822578063f369145514610842578063f5b541a61461086257600080fd5b8063a217fddf146106e8578063babdf60b146106fd578063baf029051461072b578063bce8340614610787578063d547741f146107a757600080fd5b80637fa4cacb116100f25780637fa4cacb1461063457806381d12c58146106545780638752bd9d1461068857806391d14854146106a857806394985ddd146106c857600080fd5b80635b7baf64146105765780635d4bc0ce146105965780635fba3171146105cd5780636ecc20da146105ed5780637c903fc01461060057600080fd5b80632a596800116101bc57806336734e341161018057806336734e34146104bf5780633ddf078f146104df5780634239a50c146104f257806352c8c6d71461051257806353b7a59b1461055657600080fd5b80632a596800146103fe5780632f2ff15d14610432578063317f30591461045257806336568abe14610472578063365e36581461049257600080fd5b80630df71602116102035780630df71602146103105780631a0187f5146103325780631e6cd395146103805780631fe96857146103a0578063248a9ca3146103c057600080fd5b8063013805c51461023557806301ffc9a714610277578063039be558146102a7578063043a1c9a146102f0575b600080fd5b34801561024157600080fd5b5061025561025036600461493b565b610884565b604080519283526001600160a01b039091166020830152015b60405180910390f35b34801561028357600080fd5b5061029761029236600461495c565b6108c9565b604051901515815260200161026e565b3480156102b357600080fd5b506102db6102c23660046148f4565b6008602052600090815260409020805460019091015482565b6040805192835260208301919091520161026e565b3480156102fc57600080fd5b5061029761030b36600461482e565b610900565b34801561031c57600080fd5b5061033061032b3660046148f4565b610ac3565b005b34801561033e57600080fd5b5061036861034d3660046148f4565b600c602052600090815260409020546001600160a01b031681565b6040516001600160a01b03909116815260200161026e565b34801561038c57600080fd5b5061029761039b3660046148f4565b610cc7565b3480156103ac57600080fd5b506102976103bb3660046147f6565b610e9d565b3480156103cc57600080fd5b506103f06103db3660046148f4565b60009081526020819052604090206001015490565b60405190815260200161026e565b34801561040a57600080fd5b506102db6104193660046148f4565b6006602052600090815260409020805460019091015482565b34801561043e57600080fd5b5061033061044d36600461490c565b610f1b565b34801561045e57600080fd5b5061033061046d3660046148f4565b610f45565b34801561047e57600080fd5b5061033061048d36600461490c565b611164565b34801561049e57600080fd5b506104b26104ad3660046148f4565b6111e2565b60405161026e9190614d35565b3480156104cb57600080fd5b506103306104da36600461499c565b61126a565b6103306104ed366004614b04565b61161b565b3480156104fe57600080fd5b5061033061050d3660046148f4565b611e2b565b34801561051e57600080fd5b5061053261052d36600461490c565b611ff4565b6040805182518152602080840151908201529181015115159082015260600161026e565b34801561056257600080fd5b50600d54610368906001600160a01b031681565b34801561058257600080fd5b506103306105913660046148f4565b612089565b3480156105a257600080fd5b506105b66105b13660046148f4565b61232a565b60405161026e9b9a99989796959493929190614da8565b3480156105d957600080fd5b506103306105e83660046148f4565b6123a8565b6103306105fb3660046148f4565b61263b565b34801561060c57600080fd5b506103f07fde5ee446972f4e39ab62c03aa34b2096680a875c3fdb3eb2f947cbb93341c05881565b34801561064057600080fd5b5061033061064f3660046147f6565b61279c565b34801561066057600080fd5b506102db61066f3660046148f4565b6005602052600090815260409020805460019091015482565b34801561069457600080fd5b506103f06106a3366004614b32565b6127ca565b3480156106b457600080fd5b506102976106c336600461490c565b612d14565b3480156106d457600080fd5b506103306106e336600461493b565b612d3d565b3480156106f457600080fd5b506103f0600081565b34801561070957600080fd5b5061071d610718366004614859565b612dbf565b60405161026e929190614d8d565b34801561073757600080fd5b5061076a6107463660046148f4565b600b6020526000908152604090208054600182015460029092015490919060ff1683565b60408051938452602084019290925215159082015260600161026e565b34801561079357600080fd5b506103306107a2366004614acc565b6131b8565b3480156107b357600080fd5b506103306107c236600461490c565b61347c565b3480156107d357600080fd5b506103306107e2366004614a6f565b6134a1565b3480156107f357600080fd5b5061080761080236600461493b565b6136c3565b6040805193845260208401929092529082015260600161026e565b34801561082e57600080fd5b5061029761083d3660046148a0565b6136f9565b34801561084e57600080fd5b5061036861085d36600461493b565b61390d565b34801561086e57600080fd5b506103f0600080516020614fe983398151915281565b600960205281600052604060002081815481106108a057600080fd5b6000918252602090912060029091020180546001909101549092506001600160a01b0316905082565b60006001600160e01b03198216637965db0b60e01b14806108fa57506301ffc9a760e01b6001600160e01b03198316145b92915050565b600080600a838154811061092457634e487b7160e01b600052603260045260246000fd5b60009182526020909120604080516101808101909152600c909202018054829060ff16600681111561096657634e487b7160e01b600052602160045260246000fd5b600681111561098557634e487b7160e01b600052602160045260246000fd5b81526001820154602080830191909152600283015460408084019190915260038401546001600160a01b03908116606085015260048501546080850152600585015460a085015260068501541660c0840152600784015460e084015260088401546101008401526009840154610120840152600a84018054825181850281018501909352808352610140909401939192909190830182828015610a5157602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610a33575b5050509183525050600b82015460209091019060ff166002811115610a8657634e487b7160e01b600052602160045260246000fd5b6002811115610aa557634e487b7160e01b600052602160045260246000fd5b90525060c001516001600160a01b0385811691161491505092915050565b60026001541415610aef5760405162461bcd60e51b8152600401610ae690614e6c565b60405180910390fd5b6002600155600080516020614fe9833981519152610b0c81613ab6565b6000600a8381548110610b2f57634e487b7160e01b600052603260045260246000fd5b6000918252602080832086845260089091526040909220600c90910290910191506001825460ff166006811115610b7657634e487b7160e01b600052602160045260246000fd5b14610bbc5760405162461bcd60e51b8152602060048201526016602482015275526166666c6520696e2077726f6e672073746174757360501b6044820152606401610ae6565b805460058301541015610c0b5760405162461bcd60e51b8152602060048201526017602482015276139bdd08195b9bdd59da08199d5b991cc81c985a5cd959604a1b6044820152606401610ae6565b816005015481600101541115610c635760405162461bcd60e51b815260206004820152601860248201527f446573697265642066756e6473206e6f742072616973656400000000000000006044820152606401610ae6565b815460ff191660041782556008820154610c7e908590613ac3565b50837ff2be214756d2fbc1e781d10809ddef33000009d805be55356bb348134ce21c688360050154604051610cb591815260200190565b60405180910390a25050600180555050565b600080600a8381548110610ceb57634e487b7160e01b600052603260045260246000fd5b60009182526020909120604080516101808101909152600c909202018054829060ff166006811115610d2d57634e487b7160e01b600052602160045260246000fd5b6006811115610d4c57634e487b7160e01b600052602160045260246000fd5b81526001820154602080830191909152600283015460408084019190915260038401546001600160a01b03908116606085015260048501546080850152600585015460a085015260068501541660c0840152600784015460e084015260088401546101008401526009840154610120840152600a84018054825181850281018501909352808352610140909401939192909190830182828015610e1857602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610dfa575b5050509183525050600b82015460209091019060ff166002811115610e4d57634e487b7160e01b600052602160045260246000fd5b6002811115610e6c57634e487b7160e01b600052602160045260246000fd5b9052509050600181516006811115610e9457634e487b7160e01b600052602160045260246000fd5b14159392505050565b600e54604051630723eb0360e51b81526001600160a01b038381166004830152600092169063e47d60609060240160206040518083038186803b158015610ee357600080fd5b505afa158015610ef7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108fa91906148d4565b600082815260208190526040902060010154610f3681613ab6565b610f408383613c09565b505050565b60026001541415610f685760405162461bcd60e51b8152600401610ae690614e6c565b6002600155600080516020614fe9833981519152610f8581613ab6565b6000600a8381548110610fa857634e487b7160e01b600052603260045260246000fd5b60009182526020909120600c9091020190506006815460ff166006811115610fe057634e487b7160e01b600052602160045260246000fd5b1461101c5760405162461bcd60e51b815260206004820152600c60248201526b57726f6e672073746174757360a01b6044820152606401610ae6565b600981015461102e9062278d00614ea3565b421161106d5760405162461bcd60e51b815260206004820152600e60248201526d31b630b4b6903a37b79039b7b7b760911b6044820152606401610ae6565b805460ff19166003178155600d5460058201546040516000926001600160a01b031691908381818185875af1925050503d80600081146110c9576040519150601f19603f3d011682016040523d82523d6000602084013e6110ce565b606091505b50509050806111155760405162461bcd60e51b81526020600482015260136024820152724661696c2073656e642045746820746f204d5760681b6044820152606401610ae6565b837fcdef6558dae40f2699846eedf449462daab85b1224ad7f077569ba91aaa94925836005015460405161114b91815260200190565b60405180910390a2506000600590910155505060018055565b6001600160a01b03811633146111d45760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401610ae6565b6111de8282613c8d565b5050565b606060096000838152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b8282101561125f5760008481526020908190206040805180820190915260028502909101805482526001908101546001600160a01b0316828401529083529092019101611217565b505050509050919050565b6002600154141561128d5760405162461bcd60e51b8152600401610ae690614e6c565b6002600155600080516020614fe98339815191526112aa81613ab6565b6001600a84815481106112cd57634e487b7160e01b600052603260045260246000fd5b60009182526020909120600c909102015460ff16600681111561130057634e487b7160e01b600052602160045260246000fd5b146113495760405162461bcd60e51b8152602060048201526019602482015278149859999b19481a5cc81b9bdd081a5b881858d8d95c1d1959603a1b6044820152606401610ae6565b81516000805b8281101561152d57600085828151811061137957634e487b7160e01b600052603260045260246000fd5b60200260200101519050600a87815481106113a457634e487b7160e01b600052603260045260246000fd5b90600052602060002090600c020160010154600b6000838a6040516020016113e19291906001600160a01b03929092168252602082015260400190565b6040516020818303038152906040528051906020012081526020019081526020016000206000015460016114159190614ea3565b1161151a576000604051806040016040528084600a8b8154811061144957634e487b7160e01b600052603260045260246000fd5b90600052602060002090600c0201600801546114659190614ea3565b611470906001614ea3565b81526001600160a01b03848116602092830181905260008c8152600984526040808220805460018082018355918452868420885160029092020190815587870151910180546001600160a01b03191691909516179093558251808501929092528183018d9052825180830384018152606090920183528151918401919091208152600b909252812080549293509061150783614f4c565b91905055508361151690614f4c565b9350505b508061152581614f4c565b91505061134f565b5080600a868154811061155057634e487b7160e01b600052603260045260246000fd5b90600052602060002090600c02016008015461156c9190614ea3565b600a868154811061158d57634e487b7160e01b600052603260045260246000fd5b90600052602060002090600c020160080181905550847f4da4f5fab0816c65315b6f5d15f879f96b98661133d7b3787788f291367604fb8584600a89815481106115e757634e487b7160e01b600052603260045260246000fd5b90600052602060002090600c02016008015460405161160893929190614cdf565b60405180910390a2505060018055505050565b6002600154141561163e5760405162461bcd60e51b8152600401610ae690614e6c565b60026001819055506000600a858154811061166957634e487b7160e01b600052603260045260246000fd5b600091825260209091206006600c90920201908101549091506001600160a01b03163314156116ce5760405162461bcd60e51b815260206004820152601160248201527053656c6c65722063616e6e6f742062757960781b6044820152606401610ae6565b6002600b82015460ff1660028111156116f757634e487b7160e01b600052602160045260246000fd5b148061172957506000600b82015460ff16600281111561172757634e487b7160e01b600052602160045260246000fd5b145b61176e5760405162461bcd60e51b8152602060048201526016602482015275115b9d1c9e481d1e5c19481b9bdd08185b1b1bddd95960521b6044820152606401610ae6565b600e54604051630723eb0360e51b81523360048201526001600160a01b039091169063e47d60609060240160206040518083038186803b1580156117b157600080fd5b505afa1580156117c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117e991906148d4565b156118255760405162461bcd60e51b815260206004820152600c60248201526b426c61636b6c69737465642160a01b6044820152606401610ae6565b600a81015415611a99576000805b600a8301548110156118a257846001600160a01b031683600a01828154811061186c57634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b0316141561189057600191506118a2565b8061189a81614f4c565b915050611833565b506001811515146118f55760405162461bcd60e51b815260206004820152601a60248201527f4e6f7420696e20726571756972656420636f6c6c656374696f6e0000000000006044820152606401610ae6565b6040516331a9108f60e11b815260048101849052849033906001600160a01b03831690636352211e9060240160206040518083038186803b15801561193957600080fd5b505afa15801561194d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119719190614812565b6001600160a01b0316146119c25760405162461bcd60e51b8152602060048201526018602482015277139bdd081d1a19481bdddb995c881bd9881d1bdad95b925960421b6044820152606401610ae6565b604080516001600160a01b03871660208201529081018890526060810185905260009060800160408051601f1981840301815291815281516020928301206000818152600c9093529120549091506001600160a01b0316611a40576000818152600c6020526040902080546001600160a01b03191633179055611a95565b6000818152600c60205260409020546001600160a01b03163314611a955760405162461bcd60e51b815260206004820152600c60248201526b1d1bdad95b9259081d5cd95960a21b6044820152606401610ae6565b5050505b33611adb5760405162461bcd60e51b81526020600482015260126024820152711b5cd9cb9cd95b99195c881a5cc81b9d5b1b60721b6044820152606401610ae6565b60008411611b1a5760405162461bcd60e51b815260206004820152600c60248201526b0686f774d616e7920697320360a41b6044820152606401610ae6565b6001815460ff166006811115611b4057634e487b7160e01b600052602160045260246000fd5b14611b895760405162461bcd60e51b8152602060048201526019602482015278149859999b19481a5cc81b9bdd081a5b881858d8d95c1d1959603a1b6044820152606401610ae6565b6000611b958686613cf2565b90506000816020015111611bde5760405162461bcd60e51b815260206004820152601060248201526f1a59081b9bdd081cdd5c1c1bdc9d195960821b6044820152606401610ae6565b80604001513414611c3d5760405162461bcd60e51b8152602060048201526024808201527f6d73672e76616c7565206d75737420626520657175616c20746f2074686520706044820152637269636560e01b6064820152608401610ae6565b6040805133602082015290810187905260009060600160408051601f1981840301815291815281516020928301206001860154858401516000838152600b9095529290932054909350611c909190614ea3565b1115611cde5760405162461bcd60e51b815260206004820152601760248201527f426f7567687420746f6f206d616e7920656e74726965730000000000000000006044820152606401610ae6565b6000604051806040016040528084602001518660080154611cff9190614ea3565b81523360209182015260008a81526009825260408120805460018082018355918352838320855160029092020190815592840151920180546001600160a01b0319166001600160a01b03909316929092179091556005860180549293503492909190611d6c908490614ea3565b909155505060208301516008850154611d859190614ea3565b60088501556020808401516000848152600b90925260408220805491929091611daf908490614ea3565b90915550506000828152600b602052604081206001018054349290611dd5908490614ea3565b90915550506008840154604080519182526020820189905233918a917fd746af8dc82f9bed98cea0fe0264eb1c3d2e5f7bcc77fc5efb429c79df40788791015b60405180910390a3505060018055505050505050565b6000600a8281548110611e4e57634e487b7160e01b600052603260045260246000fd5b600091825260208083208584526008825260409384902084518086019095528054855260010154918401919091526006600c90920201908101549092506001600160a01b03163314611ed35760405162461bcd60e51b815260206004820152600e60248201526d2737ba103a34329039b2b63632b960911b6044820152606401610ae6565b6001825460ff166006811115611ef957634e487b7160e01b600052602160045260246000fd5b14611f465760405162461bcd60e51b815260206004820152601d60248201527f526166666c65206e6f7420696e206163636570746564207374617475730000006044820152606401610ae6565b805160058301541015611f955760405162461bcd60e51b8152602060048201526017602482015276139bdd08195b9bdd59da08199d5b991cc81c985a5cd959604a1b6044820152606401610ae6565b815460ff191660021782556008820154611fb0908490613ac3565b50827f66859952a354270d9bd258f064bfb08464306538d8a01f12e1b9c6be7def11058360050154604051611fe791815260200190565b60405180910390a2505050565b61201a604051806060016040528060008152602001600081526020016000151581525090565b50604080516001600160a01b039290921660208084019190915282820193909352805180830382018152606083018083528151918501919091206000908152600b9094529281902060c0830190915280548352600181015460808301526002015460ff16151560a09091015290565b600260015414156120ac5760405162461bcd60e51b8152600401610ae690614e6c565b60026001819055506000600a82815481106120d757634e487b7160e01b600052603260045260246000fd5b60009182526020909120600c9091020190506006815460ff16600681111561210f57634e487b7160e01b600052602160045260246000fd5b1461214b5760405162461bcd60e51b815260206004820152600c60248201526b77726f6e672073746174757360a01b6044820152606401610ae6565b600981015461215d9062278d00614ea3565b4211156121a15760405162461bcd60e51b815260206004820152601260248201527118db185a5b481d1a5b5948195e1c1a5c995960721b6044820152606401610ae6565b6040805133602080830191909152818301859052825180830384018152606090920183528151918101919091206000908152600b90915220600281015460ff16156122215760405162461bcd60e51b815260206004820152601060248201526f185b1c9958591e481c99599d5b99195960821b6044820152606401610ae6565b806001015482600501546122359190614eee565b600583015560028101805460ff1916600190811790915581015460405160009133918381818185875af1925050503d806000811461228f576040519150601f19603f3d011682016040523d82523d6000602084013e612294565b606091505b50509050806122d85760405162461bcd60e51b815260206004820152601060248201526f11985a5b081cd95b99081c99599d5b9960821b6044820152606401610ae6565b336001600160a01b0316847ffe438001a6dd8298a7672e341088143b150c2227f220b57280a002f5357612b7846001015460405161231891815260200190565b60405180910390a35050600180555050565b600a818154811061233a57600080fd5b60009182526020909120600c9091020180546001820154600283015460038401546004850154600586015460068701546007880154600889015460098a0154600b909a015460ff998a169b50979996986001600160a01b03968716989597949690931694919390929091168b565b600260015414156123cb5760405162461bcd60e51b8152600401610ae690614e6c565b6002600155600080516020614fe98339815191526123e881613ab6565b6000600a838154811061240b57634e487b7160e01b600052603260045260246000fd5b60009182526020909120600c9091020190506005815460ff16600681111561244357634e487b7160e01b600052602160045260246000fd5b1415801561247557506003815460ff16600681111561247257634e487b7160e01b600052602160045260246000fd5b14155b80156124a557506002815460ff1660068111156124a257634e487b7160e01b600052602160045260246000fd5b14155b80156124d557506004815460ff1660068111156124d257634e487b7160e01b600052602160045260246000fd5b14155b801561250557506006815460ff16600681111561250257634e487b7160e01b600052602160045260246000fd5b14155b6125405760405162461bcd60e51b815260206004820152600c60248201526b57726f6e672073746174757360a01b6044820152606401610ae6565b6001815460ff16600681111561256657634e487b7160e01b600052602160045260246000fd5b14156125e757600681015460028201546040516000926001600160a01b031691908381818185875af1925050503d80600081146125bf576040519150601f19603f3d011682016040523d82523d6000602084013e6125c4565b606091505b50509050806125e55760405162461bcd60e51b8152600401610ae690614e3e565b505b805460ff19166006178155426009820155600581015460405190815283907fd512a34b0f0618078770fcd85d974df1ab46a7882e8b3d45aa91764f4961aed29060200160405180910390a250506001805550565b6002600154141561265e5760405162461bcd60e51b8152600401610ae690614e6c565b60026001819055506000600a828154811061268957634e487b7160e01b600052603260045260246000fd5b600091825260208220600c909102019150815460ff1660068111156126be57634e487b7160e01b600052602160045260246000fd5b146127005760405162461bcd60e51b8152602060048201526012602482015271149859999b19481b9bdd0810d4915055115160721b6044820152606401610ae6565b348160020154146127465760405162461bcd60e51b815260206004820152601060248201526f141c9a5e99481b9bdd081cdd185ad95960821b6044820152606401610ae6565b805460ff19166001178155600681018054336001600160a01b0319909116811790915560405183907f8bb509eedfd1c4847b0a8a2b4493cf2ebb9970dc367e477cd2a8523e212dc1db90600090a3505060018055565b60006127a781613ab6565b50600d80546001600160a01b0319166001600160a01b0392909216919091179055565b6000600080516020614fe98339815191526127e481613ab6565b60008b116128265760405162461bcd60e51b815260206004820152600f60248201526e06d6178456e7472696573206973203608c1b6044820152606401610ae6565b60008a116128635760405162461bcd60e51b815260206004820152600a60248201526905072697a6520697320360b41b6044820152606401610ae6565b6113888611156128ab5760405162461bcd60e51b81526020600482015260136024820152720c6dedadad2e6e6d2dedc40e8dede40d0d2ced606b1b6044820152606401610ae6565b604080516101808101909152600090808281526020018d81526020018c815260200160006001600160a01b031681526020016000815260200160008152602001336001600160a01b03168152602001888152602001600081526020016000815260200187878080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050509082525060200185600281111561296757634e487b7160e01b600052602160045260246000fd5b9052600a8054600181810183556000929092528251600c9091027fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a801805493945084939092839160ff1916908360068111156129d357634e487b7160e01b600052602160045260246000fd5b021790555060208281015160018301556040830151600283015560608301516003830180546001600160a01b039283166001600160a01b0319918216179091556080850151600485015560a0850151600585015560c085015160068501805491909316911617905560e08301516007830155610100830151600883015561012083015160098301556101408301518051612a7392600a8501920190614713565b50610160820151600b8201805460ff19166001836002811115612aa657634e487b7160e01b600052602160045260246000fd5b0217905550505087612ae65760405162461bcd60e51b81526020600482015260096024820152684e6f2070726963657360b81b6044820152606401610ae6565b60005b88811015612c735760008a8a83818110612b1357634e487b7160e01b600052603260045260246000fd5b9050606002016020013511612b5c5760405162461bcd60e51b815260206004820152600f60248201526e06e756d456e7472696573206973203608c1b6044820152606401610ae6565b600060405180606001604052808c8c85818110612b8957634e487b7160e01b600052603260045260246000fd5b9050606002016000013581526020018c8c85818110612bb857634e487b7160e01b600052603260045260246000fd5b9050606002016020013581526020018c8c85818110612be757634e487b7160e01b600052603260045260246000fd5b90506060020160400135815250905080600760006001600a80549050612c0d9190614eee565b81526020019081526020016000208360058110612c3a57634e487b7160e01b600052603260045260246000fd5b60030201600082015181600001556020820151816001015560408201518160020155905050508080612c6b90614f4c565b915050612ae9565b5060405180604001604052808b81526020018e815250600860006001600a80549050612c9f9190614eee565b815260208082019290925260400160002082518155910151600191820155600a548c91612ccb91614eee565b6040517ff6f5afeb49bc62176d1efaa06a1753999cc29bf378f1004ea916f37f41d7638a90600090a3600a54612d0390600190614eee565b9d9c50505050505050505050505050565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b336001600160a01b037f000000000000000000000000f0d54349addcf704f77ae15b96510dea15cb79521614612db55760405162461bcd60e51b815260206004820152601f60248201527f4f6e6c7920565246436f6f7264696e61746f722063616e2066756c66696c6c006044820152606401610ae6565b6111de8282613df7565b600060606000600a8681548110612de657634e487b7160e01b600052603260045260246000fd5b60009182526020909120604080516101808101909152600c909202018054829060ff166006811115612e2857634e487b7160e01b600052602160045260246000fd5b6006811115612e4757634e487b7160e01b600052602160045260246000fd5b81526001820154602080830191909152600283015460408084019190915260038401546001600160a01b03908116606085015260048501546080850152600585015460a085015260068501541660c0840152600784015460e084015260088401546101008401526009840154610120840152600a84018054825181850281018501909352808352610140909401939192909190830182828015612f1357602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612ef5575b5050509183525050600b82015460209091019060ff166002811115612f4857634e487b7160e01b600052602160045260246000fd5b6002811115612f6757634e487b7160e01b600052602160045260246000fd5b9052506101408101515190915015613199576000805b82610140015151811015612fec57866001600160a01b03168361014001518281518110612fba57634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b03161415612fda5760019150612fec565b80612fe481614f4c565b915050612f7d565b50806130355760006040518060400160405280601a81526020017f4e6f7420696e20726571756972656420636f6c6c656374696f6e0000000000008152509350935050506131af565b6040516331a9108f60e11b81526004810186905286906001600160a01b038a81169190831690636352211e9060240160206040518083038186803b15801561307c57600080fd5b505afa158015613090573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130b49190614812565b6001600160a01b03161461310157600060405180604001604052806018815260200177139bdd081d1a19481bdddb995c881bd9881d1bdad95b925960421b815250945094505050506131af565b604080516001600160a01b03891660208201529081018990526060810187905260009060800160408051808303601f1901815291815281516020928301206000818152600c9093529120549091506001600160a01b038b81169116146131955760006040518060400160405280600c81526020016b1d1bdad95b9259081d5cd95960a21b81525095509550505050506131af565b5050505b5050604080516020810190915260008152600191505b94509492505050565b7fde5ee446972f4e39ab62c03aa34b2096680a875c3fdb3eb2f947cbb93341c0586131e281613ab6565b600260015414156132055760405162461bcd60e51b8152600401610ae690614e6c565b6002600155604080516001600160a01b03841660208201529081018590526000906060016040516020818303038152906040528051906020012090506000600a868154811061326457634e487b7160e01b600052603260045260246000fd5b60009182526020909120600c9091020190506001600b82015460ff16600281111561329f57634e487b7160e01b600052602160045260246000fd5b14806132d157506002600b82015460ff1660028111156132cf57634e487b7160e01b600052602160045260246000fd5b145b6133165760405162461bcd60e51b8152602060048201526016602482015275115b9d1c9e481d1e5c19481b9bdd08185b1b1bddd95960521b6044820152606401610ae6565b600060405180604001604052808784600801546133339190614ea3565b81526001600160a01b0387811660209283015260008a81526009835260408120805460018082018355918352848320865160029092020190815593850151930180546001600160a01b0319169390921692909217905560088401805492935088929091906133a2908490614ea3565b90915550506000838152600b6020526040812080548892906133c5908490614ea3565b909155505060408051600180825281830190925260009160208083019080368337019050509050858160008151811061340e57634e487b7160e01b600052603260045260246000fd5b60200260200101906001600160a01b031690816001600160a01b031681525050877f4da4f5fab0816c65315b6f5d15f879f96b98661133d7b3787788f291367604fb8289866008015460405161346693929190614cdf565b60405180910390a2505060018055505050505050565b60008281526020819052604090206001015461349781613ab6565b610f408383613c8d565b600080516020614fe98339815191526134b981613ab6565b6000805b848110156136775760008781526009602052604081208787848181106134f357634e487b7160e01b600052603260045260246000fd5b905060200201358154811061351857634e487b7160e01b600052603260045260246000fd5b6000918252602090912060029091020160018101549091506001600160a01b0386811691161461358a5760405162461bcd60e51b815260206004820152601e60248201527f456e74727920646964206e6f742062656c6f6e6720746f20706c6179657200006044820152606401610ae6565b6001810180546001600160a01b031916905560008787848181106135be57634e487b7160e01b600052603260045260246000fd5b90506020020135600014156135d557506000613649565b6000898152600960205260409020600189898681811061360557634e487b7160e01b600052603260045260246000fd5b905060200201356136169190614eee565b8154811061363457634e487b7160e01b600052603260045260246000fd5b90600052602060002090600202016000015490505b8154613656908290614eee565b6136609085614ea3565b93505050808061366f90614f4c565b9150506134bd565b50604080518281526001600160a01b038516602082015287917f2cca80c1af5abb202a642a502875436822768d733462843a7c3a902b0fad99d0910160405180910390a2505050505050565b600760205281600052604060002081600581106136df57600080fd5b600302018054600182015460029092015490935090915083565b600080600a848154811061371d57634e487b7160e01b600052603260045260246000fd5b60009182526020909120604080516101808101909152600c909202018054829060ff16600681111561375f57634e487b7160e01b600052602160045260246000fd5b600681111561377e57634e487b7160e01b600052602160045260246000fd5b81526001820154602080830191909152600283015460408084019190915260038401546001600160a01b03908116606085015260048501546080850152600585015460a085015260068501541660c0840152600784015460e084015260088401546101008401526009840154610120840152600a8401805482518185028101850190935280835261014090940193919290919083018282801561384a57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161382c575b5050509183525050600b82015460209091019060ff16600281111561387f57634e487b7160e01b600052602160045260246000fd5b600281111561389e57634e487b7160e01b600052602160045260246000fd5b905250604080516001600160a01b0388166020820152908101869052909150600090606001604051602081830303815290604052805190602001209050816020015184600b6000848152602001908152602001600020600001546139029190614ea3565b119695505050505050565b600082815260096020526040812081906139279084613eb4565b6000858152600960205260408120805492935090918390811061395a57634e487b7160e01b600052603260045260246000fd5b60009182526020909120600160029092020101546001600160a01b0316905080156139885791506108fa9050565b6000825b811580156139e2575060008781526009602052604081208054839081106139c357634e487b7160e01b600052603260045260246000fd5b60009182526020909120600160029092020101546001600160a01b0316145b15613a195780613a0e57600087815260096020526040902054613a0790600190614eee565b905061398c565b613a07600182614eee565b8115613a5f5760405162461bcd60e51b8152602060048201526015602482015274105b1b081d5cd95c9cc8189b1858dadb1a5cdd1959605a1b6044820152606401610ae6565b6000878152600960205260409020805482908110613a8d57634e487b7160e01b600052603260045260246000fd5b60009182526020909120600160029092020101546001600160a01b031694506108fa9350505050565b613ac08133613fa1565b50565b600480546040516370a0823160e01b815230928101929092526000917f000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca6001600160a01b0316906370a082319060240160206040518083038186803b158015613b2b57600080fd5b505afa158015613b3f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b639190614984565b1015613bc55760405162461bcd60e51b815260206004820152602b60248201527f4e6f7420656e6f756768204c494e4b202d2066696c6c20636f6e74726163742060448201526a1dda5d1a0819985d58d95d60aa1b6064820152608401610ae6565b6000613bd5600354600454614005565b6040805180820182529586526020808701958652600083815260069091522094518555925160019094019390935550919050565b613c138282612d14565b6111de576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055613c493390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b613c978282612d14565b156111de576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b613d1660405180606001604052806000815260200160008152602001600081525090565b60005b6005811015613dd057600084815260076020526040902083908260058110613d5157634e487b7160e01b600052603260045260246000fd5b60030201541415613dbe5760008481526007602052604090208160058110613d8957634e487b7160e01b600052603260045260246000fd5b6003020160405180606001604052908160008201548152602001600182015481526020016002820154815250509150506108fa565b80613dc881614f4c565b915050613d19565b50604051806060016040528060008152602001600081526020016000815250905092915050565b6000828152600660209081526040808320815180830190925280548252600101549181018290529190613e2a9084614f67565b613e35906001614ea3565b60408051808201825285815260208082018481528651600090815260058352849020835181559051600190910155855183518881529182018590529394509092917f7c40e661b8212d0c4f60ac6e6ebed99c28680c7b3ede5b82f3b0254543f62fca910160405180910390a28251613ead9083614198565b5050505050565b8154600090613ec5575060006108fa565b82546000905b80821015613f36576000613edf838361450f565b905084868281548110613f0257634e487b7160e01b600052603260045260246000fd5b9060005260206000209060020201600001541115613f2257809150613f30565b613f2d816001614ea3565b92505b50613ecb565b600082118015613f8057508385613f4e600185614eee565b81548110613f6c57634e487b7160e01b600052603260045260246000fd5b906000526020600020906002020160000154145b15613f9957613f90600183614eee565b925050506108fa565b5090506108fa565b613fab8282612d14565b6111de57613fc3816001600160a01b03166014614531565b613fce836020614531565b604051602001613fdf929190614c3a565b60408051601f198184030181529082905262461bcd60e51b8252610ae691600401614e2b565b60007f000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca6001600160a01b0316634000aea07f000000000000000000000000f0d54349addcf704f77ae15b96510dea15cb795284866000604051602001614075929190918252602082015260400190565b6040516020818303038152906040526040518463ffffffff1660e01b81526004016140a293929190614caf565b602060405180830381600087803b1580156140bc57600080fd5b505af11580156140d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140f491906148d4565b50600083815260026020818152604080842054815180840189905280830186905230606082015260808082018390528351808303909101815260a090910190925281519183019190912093879052919052614150906001614ea3565b6000858152600260205260409020556141908482604080516020808201949094528082019290925280518083038201815260609092019052805191012090565b949350505050565b600260015414156141bb5760405162461bcd60e51b8152600401610ae690614e6c565b60026001819055506000600a83815481106141e657634e487b7160e01b600052603260045260246000fd5b60009182526020909120600c9091020190506002815460ff16600681111561421e57634e487b7160e01b600052602160045260246000fd5b148061424d57506004815460ff16600681111561424b57634e487b7160e01b600052602160045260246000fd5b145b6142925760405162461bcd60e51b8152602060048201526016602482015275526166666c6520696e2077726f6e672073746174757360501b6044820152606401610ae6565b600481018290556142a3838361390d565b6003820180546001600160a01b03929092166001600160a01b031990921682179055815460ff19166005178255600282015460405160009291908381818185875af1925050503d8060008114614315576040519150601f19603f3d011682016040523d82523d6000602084013e61431a565b606091505b505090508061433b5760405162461bcd60e51b8152600401610ae690614e3e565b6000612710836007015484600501546143549190614ecf565b61435e9190614ebb565b905060008184600501546143729190614eee565b60068501546040519192506000916001600160a01b039091169083908381818185875af1925050503d80600081146143c6576040519150601f19603f3d011682016040523d82523d6000602084013e6143cb565b606091505b50509050806143ec5760405162461bcd60e51b8152600401610ae690614e3e565b600d546040516000916001600160a01b03169085908381818185875af1925050503d8060008114614439576040519150601f19603f3d011682016040523d82523d6000602084013e61443e565b606091505b50509050806144875760405162461bcd60e51b81526020600482015260156024820152744661696c65642073656e642045746820746f204d5760581b6044820152606401610ae6565b877f7378e11c2b0ec7514bbf7ba369980eedcba0bca03e116dc9e7138f7748e211d6856040516144b991815260200190565b60405180910390a26003860154600587015460408051918252602082018a90526001600160a01b03909216918a917fe0b2a72a0644b093aac275024c05c7c28851a0b572557a32241d13634a0f3e089101611e15565b600061451e6002848418614ebb565b61452a90848416614ea3565b9392505050565b60606000614540836002614ecf565b61454b906002614ea3565b67ffffffffffffffff81111561457157634e487b7160e01b600052604160045260246000fd5b6040519080825280601f01601f19166020018201604052801561459b576020820181803683370190505b509050600360fc1b816000815181106145c457634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061460157634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a9053506000614625846002614ecf565b614630906001614ea3565b90505b60018111156146c4576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811061467257634e487b7160e01b600052603260045260246000fd5b1a60f81b82828151811061469657634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a90535060049490941c936146bd81614f35565b9050614633565b50831561452a5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610ae6565b828054828255906000526020600020908101928215614768579160200282015b8281111561476857825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190614733565b50614774929150614778565b5090565b5b808211156147745760008155600101614779565b803561479881614fd3565b919050565b60008083601f8401126147ae578182fd5b50813567ffffffffffffffff8111156147c5578182fd5b6020830191508360208260051b85010111156147e057600080fd5b9250929050565b80356003811061479857600080fd5b600060208284031215614807578081fd5b813561452a81614fd3565b600060208284031215614823578081fd5b815161452a81614fd3565b60008060408385031215614840578081fd5b823561484b81614fd3565b946020939093013593505050565b6000806000806080858703121561486e578182fd5b843561487981614fd3565b935060208501359250604085013561489081614fd3565b9396929550929360600135925050565b6000806000606084860312156148b4578283fd5b83356148bf81614fd3565b95602085013595506040909401359392505050565b6000602082840312156148e5578081fd5b8151801515811461452a578182fd5b600060208284031215614905578081fd5b5035919050565b6000806040838503121561491e578182fd5b82359150602083013561493081614fd3565b809150509250929050565b6000806040838503121561494d578182fd5b50508035926020909101359150565b60006020828403121561496d578081fd5b81356001600160e01b03198116811461452a578182fd5b600060208284031215614995578081fd5b5051919050565b600080604083850312156149ae578182fd5b8235915060208084013567ffffffffffffffff808211156149cd578384fd5b818601915086601f8301126149e0578384fd5b8135818111156149f2576149f2614fbd565b8060051b604051601f19603f83011681018181108582111715614a1757614a17614fbd565b604052828152858101935084860182860187018b1015614a35578788fd5b8795505b83861015614a5e57614a4a8161478d565b855260019590950194938601938601614a39565b508096505050505050509250929050565b60008060008060608587031215614a84578182fd5b84359350602085013567ffffffffffffffff811115614aa1578283fd5b614aad8782880161479d565b9094509250506040850135614ac181614fd3565b939692955090935050565b600080600060608486031215614ae0578081fd5b83359250602084013591506040840135614af981614fd3565b809150509250925092565b60008060008060808587031215614b19578182fd5b8435935060208501359250604085013561489081614fd3565b6000806000806000806000806000806101008b8d031215614b51578788fd5b8a35995060208b0135985060408b0135975060608b0135965060808b013567ffffffffffffffff80821115614b84578788fd5b818d0191508d601f830112614b97578788fd5b813581811115614ba5578889fd5b8e6020606083028501011115614bb9578889fd5b6020830198508097505060a08d0135955060c08d0135915080821115614bdd578485fd5b50614bea8d828e0161479d565b9094509250614bfd905060e08c016147e7565b90509295989b9194979a5092959850565b60008151808452614c26816020860160208601614f05565b601f01601f19169290920160200192915050565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351614c72816017850160208801614f05565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351614ca3816028840160208801614f05565b01602801949350505050565b60018060a01b0384168152826020820152606060408201526000614cd66060830184614c0e565b95945050505050565b606080825284519082018190526000906020906080840190828801845b82811015614d215781516001600160a01b031684529284019290840190600101614cfc565b505050908301949094525060400152919050565b602080825282518282018190526000919060409081850190868401855b82811015614d80578151805185528601516001600160a01b0316868501529284019290850190600101614d52565b5091979650505050505050565b82151581526040602082015260006141906040830184614c0e565b610160810160078d10614dbd57614dbd614fa7565b8c82528b60208301528a604083015260018060a01b03808b1660608401528960808401528860a084015280881660c0840152508560e0830152846101008301528361012083015260038310614e1457614e14614fa7565b826101408301529c9b505050505050505050505050565b60208152600061452a6020830184614c0e565b6020808252601490820152732330b4b632b2103a379039b2b7321022ba3432b960611b604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60008219821115614eb657614eb6614f7b565b500190565b600082614eca57614eca614f91565b500490565b6000816000190483118215151615614ee957614ee9614f7b565b500290565b600082821015614f0057614f00614f7b565b500390565b60005b83811015614f20578181015183820152602001614f08565b83811115614f2f576000848401525b50505050565b600081614f4457614f44614f7b565b506000190190565b6000600019821415614f6057614f60614f7b565b5060010190565b600082614f7657614f76614f91565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114613ac057600080fdfe523a704056dcd17bcf83bed8b68c59416dac1119be77755efe3bde0a64e46e0ca26469706673582212209e8d2fbf52ca937a29e8344115855b614692a912217b2a69bae5b96d55b7520f64736f6c63430008040033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000003be4bef162cd158887cfdca89a34fae107ab2c74000000000000000000000000f0d54349addcf704f77ae15b96510dea15cb7952000000000000000000000000514910771af9ca656af840dff83e8264ecf986caaa77729d3466ca35ae8d28b3bbac7cc36a5031efdc430821c02bc31a238af4450000000000000000000000000000000000000000000000000000000000000001
-----Decoded View---------------
Arg [0] : _blacklistManager (address): 0x3BE4BeF162cD158887Cfdca89a34fAe107AB2c74
Arg [1] : _vrfCoordinator (address): 0xf0d54349aDdcf704F77AE15b96510dEA15cb7952
Arg [2] : _linkToken (address): 0x514910771AF9Ca656af840dff83E8264EcF986CA
Arg [3] : _keyHash (bytes32): 0xaa77729d3466ca35ae8d28b3bbac7cc36a5031efdc430821c02bc31a238af445
Arg [4] : _mainetFee (bool): True
-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 0000000000000000000000003be4bef162cd158887cfdca89a34fae107ab2c74
Arg [1] : 000000000000000000000000f0d54349addcf704f77ae15b96510dea15cb7952
Arg [2] : 000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca
Arg [3] : aa77729d3466ca35ae8d28b3bbac7cc36a5031efdc430821c02bc31a238af445
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000001
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
ETH | 100.00% | $22.48 | 18 | $404.64 |
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.