Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
5.2 ETH
Eth Value
$12,643.75 (@ $2,431.49/ETH)Token Holdings
More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 7,175 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Create Raffle | 20892392 | 2 days ago | IN | 0 ETH | 0.00414693 | ||||
Create Raffle | 20892370 | 2 days ago | IN | 0 ETH | 0.01159731 | ||||
Claim Refund | 20874582 | 4 days ago | IN | 0 ETH | 0.00025419 | ||||
Claim Refund | 20874401 | 4 days ago | IN | 0 ETH | 0.00027053 | ||||
Claim Refund | 20873535 | 4 days ago | IN | 0 ETH | 0.00032595 | ||||
Claim Refund | 20872567 | 4 days ago | IN | 0 ETH | 0.00089521 | ||||
Claim Refund | 20872560 | 4 days ago | IN | 0 ETH | 0.00088675 | ||||
Claim Refund | 20869640 | 5 days ago | IN | 0 ETH | 0.00066573 | ||||
Claim Refund | 20865272 | 5 days ago | IN | 0 ETH | 0.00075765 | ||||
Claim Refund | 20865023 | 5 days ago | IN | 0 ETH | 0.00069864 | ||||
Claim Refund | 20865010 | 5 days ago | IN | 0 ETH | 0.0006657 | ||||
Claim Refund | 20864909 | 5 days ago | IN | 0 ETH | 0.00073354 | ||||
Claim Refund | 20864808 | 5 days ago | IN | 0 ETH | 0.00090968 | ||||
Enter Raffles | 20864708 | 5 days ago | IN | 0.98 ETH | 0.00192006 | ||||
Enter Raffles | 20864700 | 5 days ago | IN | 0.024 ETH | 0.00229525 | ||||
Enter Raffles | 20864693 | 5 days ago | IN | 0.024 ETH | 0.00229228 | ||||
Enter Raffles | 20864690 | 5 days ago | IN | 0.024 ETH | 0.00230924 | ||||
Enter Raffles | 20864221 | 5 days ago | IN | 0.024 ETH | 0.00165449 | ||||
Enter Raffles | 20864159 | 5 days ago | IN | 0.024 ETH | 0.00184956 | ||||
Enter Raffles | 20863341 | 6 days ago | IN | 0.024 ETH | 0.00093953 | ||||
Enter Raffles | 20860993 | 6 days ago | IN | 0.024 ETH | 0.00041551 | ||||
Enter Raffles | 20858316 | 6 days ago | IN | 0.048 ETH | 0.00121636 | ||||
Enter Raffles | 20857851 | 6 days ago | IN | 0.525 ETH | 0.00078141 | ||||
Enter Raffles | 20857769 | 6 days ago | IN | 0.024 ETH | 0.00087551 | ||||
Enter Raffles | 20852788 | 7 days ago | IN | 0.024 ETH | 0.00058991 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
20874582 | 4 days ago | 0.024 ETH | ||||
20874401 | 4 days ago | 0.024 ETH | ||||
20873535 | 4 days ago | 0.024 ETH | ||||
20872567 | 4 days ago | 0.024 ETH | ||||
20872560 | 4 days ago | 0.024 ETH | ||||
20869640 | 5 days ago | 0.024 ETH | ||||
20865272 | 5 days ago | 0.024 ETH | ||||
20865023 | 5 days ago | 0.048 ETH | ||||
20865010 | 5 days ago | 0.525 ETH | ||||
20864909 | 5 days ago | 0.024 ETH | ||||
20864808 | 5 days ago | 0.98 ETH | ||||
19707442 | 167 days ago | 0.012 ETH | ||||
19513046 | 194 days ago | 0.012 ETH | ||||
19510521 | 195 days ago | 0.012 ETH | ||||
19233308 | 234 days ago | 0.012 ETH | ||||
19141590 | 246 days ago | 1.38975 ETH | ||||
19141590 | 246 days ago | 26.40525 ETH | ||||
19042223 | 260 days ago | 0.0866 ETH | ||||
19042223 | 260 days ago | 1.6454 ETH | ||||
19027426 | 262 days ago | 0.024 ETH | ||||
19020764 | 263 days ago | 0.012 ETH | ||||
19020755 | 263 days ago | 0.012 ETH | ||||
18982156 | 269 days ago | 0.4995 ETH | ||||
18982156 | 269 days ago | 9.4905 ETH | ||||
18901030 | 280 days ago | 0.012 ETH |
Loading...
Loading
Contract Name:
RaffleV2
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 888888 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.20; import {LowLevelWETH} from "@looksrare/contracts-libs/contracts/lowLevelCallers/LowLevelWETH.sol"; import {LowLevelERC20Transfer} from "@looksrare/contracts-libs/contracts/lowLevelCallers/LowLevelERC20Transfer.sol"; import {LowLevelERC721Transfer} from "@looksrare/contracts-libs/contracts/lowLevelCallers/LowLevelERC721Transfer.sol"; import {LowLevelERC1155Transfer} from "@looksrare/contracts-libs/contracts/lowLevelCallers/LowLevelERC1155Transfer.sol"; import {OwnableTwoSteps} from "@looksrare/contracts-libs/contracts/OwnableTwoSteps.sol"; import {PackableReentrancyGuard} from "@looksrare/contracts-libs/contracts/PackableReentrancyGuard.sol"; import {Pausable} from "@looksrare/contracts-libs/contracts/Pausable.sol"; import {ITransferManager} from "@looksrare/contracts-transfer-manager/contracts/interfaces/ITransferManager.sol"; import {VRFCoordinatorV2Interface} from "@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol"; import {VRFConsumerBaseV2} from "@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol"; import {Arrays} from "./libraries/Arrays.sol"; import {WinningEntrySearchLogicV2} from "./WinningEntrySearchLogicV2.sol"; import {IRaffleV2} from "./interfaces/IRaffleV2.sol"; // .................................................................................................... // .......................................,,,,,,....................................................... // ....................................,;+??????*;;:..................,,,,,,,,......................... // ..................................,+?????????????*;,............:;*????????*;,...................... // ................................,+??????????????*???+,.......:+*??????????????*:.................... // ..............................:+?????????*????????*???+:,.,;*???????????????????*,.................. // ............................,*???????????%%%%%%%%%%??*???*???????????????????????*,................. // ..........................,;???????????%%??????????%%%?*????????????????????????*?;................. // .........................:???????????%%???????????????%%???????*?????????????*?**?*................. // ........................:%%%???????%%?*??????????????**?%?**???%%%%%%%%%%%%%%??????,,,,............. // ......................,*SSSSS?????%?*??????????*??????%??%%??????????????***???????????*;:.......... // .....................:%S%%%%SS??????????????*??%%%%%%%?????%%%%??*????????????????????????+,........ // ....................:SS%%%%%%#?*????????????%%%????**???????*??%%%?*??%%%%%%%?????????%%%%%:........ // ....................+S?%%%%%%S%*?????????*?%%?**??%%%%%%%%%%%??*?%??%%??????????%%%%%?????%?+,...... // ..................,;%%%%%%%%%%S*???????*??%?*??%%%???????????%%%??S%????%%%%%%???????%%%%????*,..... // .................;?S#%%%%?SS%%S*???????%%%?*?%%??*??****????????%%%?%%%?????????*++++*?%%%%%??:..... // ...............,*%?S%%%%%%S%%SS*????%%%????%%??*????%SSS##S***?????%???*????*;,,:::;:,,:+???%S+..... // ..............,*?*?S%%%%%%#SSS?????%???*?%%???????%@@@@@@##S:.,:+????????+:,..:%@@@%@#*,..:*???+.... // ..............+????S%%%%%%S%???????????%%??*???+:+#@@@@@SS@@#:...,;????+,....;@@@@@%@@@#+...:???:... // .............:?????S%%%%%%S*????%%%%%%%??????+,.,#+S@@@;.+@@@%.....+%*,.....,S@@@@@?;*#@@+...,+?,... // .............*?????S%%%%%%S*????%**???**???+,...?@#@@@S..,#@@@;....;*.......+%?@@@%...;@@#,....;:... // ............;??????S%%%%%%S?????%%???????+,....,#@@@@@#:.,#@@@%....;,.......S@@@@@*....#@@+....,;... // ...........,???????S%%%%%%S????????%%%%:,......:@@@@@@@S*%@@@@#,..,;.......,#@@@@@?....S@@%....:;... // ...........;???????%S%%%%%SS*??????**???:......:@@@@@@@@@@@@@@@+..::.......,@@@@@@#;,.;@@@#,..,+,... // ..........,?????????S%%%%%%S?????????????*:....,#@@@@@@@@@@@@@@?.,+:.......,@@@@@@@@#S@@@@@:.;+,.... // ..........;????????*S%%%%%%SS*?????????????*:...S@@@@@@@@@@@@@@S+?%*::,....,#@@@@@@@@@@@@@@?*%;..... // ..........*????????*SS%S#S?%S??????????%?**??*;,*@@@@@@@@@@@@#S%???%???**+;:S@@@@@@@@##S%?????:..... // .........:?????????*%#S%%S%%%S???*??????%%%??????####@@@@#S%?***?%%?????????%%%%??????*****?*:...... // .........*?????????*%#?*%S%%%S?*?%%%%%%%%?%%%%%%%%???????****??%%%????????????????????????%;........ // ........:?????????*%#?**S%?%%%S%%%?????%%%%%????????%%%%%%%%%%%?????????????%%%%%%%%%%%%%%+......... // ........*??????????#%*?*%SSSS%S#???????????%%%%%??***???????????????????????*??*??*?????*%+:........ // .......:?????????*%#?????%%%S%%S%??????????????%%%%%???***??????????????????????????**??%%%%+....... // .......*??????????#%*???***S%%%%#????S#S%%?????????%%%%%%?????*?????????????????**???%%%%????....... // ......:?????????*SS*???????SSSS%SS??SS%S#%%%%???????????%%%%%%%%?????????????????%%%%%???????....... // ......+????????*?#????????????%S%SSSS%%%SS?%%%%%%?????????????%%%%%%%%%%%%%%%%%%%%?????????%+....... // ......*?????????#S??????????*?S%%%SS%%%%%S%????%%%%%?????????????????????????????????????%%+,....... // ......*???????*%#SS?????????*%%%%%%%%%%%%%#???????%%%%%%%?????????????????????????????%%?+:......... // ......*????????SS%SS?*?????*%%%%%%%%%%%%%%SS???????????%%%%%%%??????????????????%%%%%%%%*........... // .....;S%???????#%%%SS?*???*%#%%%%%%%%%%%%%%#%%?????????????%%%%%%%%%%%%%%%%%%%%%%%%??????,.......... // ...,?SSS%*???*SS%%%%S#?*?*%#%#%%%%%%%%%%%%%S?%%%%????????????????????????????????????????,.......... // ...?S%%%S?*???S%%%%%%S#?*?#?*%SS%%%%%%%%%%%S?*??%%%%???????????????????????????????????%?........... // .,?S%%%%SS%?*%S%%%%%%%SS?S%*?*?SS%%%%%%%%%%S????*??%%%%%%%????????????????????????????%%:........... // .*#%%%%%%%SS%S%%%%%%%%%S#S??????%S#S%%%%?%SS???????*?????%%%%%%%%%%%%%%%%%??????????%%*:............ // ;S%%%%%%%%%S#S%%%%%%%%%S#????????*?SSSSSSS#??????????????*?????????%%%%%%%%%%%%%S%??+,.............. // %S%%%%%%%%%SS%%%%%%%%%%S%*????????**%%%%%##????????????????????????*******??????+,.................. // S%%%%%%%%%SS%%%%%%%%%%S#%%?????**???****?SS%*??????????????????????????????**+:,.................... // %%%%%%%%S#S%%%%%%%%%%%S???%%%%%%?????????SSS*??????????????????***??+;;;::,......................... // %%%%%%%S#S%%%%%%%%%%%SS?***??????%%%%%%%%SSS?????????????????????%?:................................ // %%%%%%SSS%%%%%%%%%%%S#SS%????*****???????%SS%%%%%%%%%%%%%%%%%??%%+,................................. // %%%%%%%%%%%%%%%%%%%%SS%SSSSSS%%????******%SS?************?***?%*:................................... // %%%%%%%%%%%%%%%%%%%%#S%%%%%%SSSSSSS%%%???%SS%???????????????%S#+.................................... // %%%%%%%%%%%%%%%%%%%S#%%%%%%%%%%%%%SSSSSSSS#%#SSSSSSSSSSSSSSSS%S%,................................... // %%%%%%%%%%%%%%%%%%%#S%%%%%%%%%%%%%%%%%S####%#%%%%%%%%%%%%%%%%%%S+................................... // %%%%%%%%%%%%%%%%%%S#%%%%%%%%%%%%%%%%%%#S%S@%#S%%%%%%%%%%%%%%%%%S%,.................................. // %%%%%%%%%%%%%%%%%%#S%%%%%%%%%%%%%%%%%SS%#S#%SS%%%%%%%%%%%%%%%%%%S*.................................. // %%%%%%%%%%%%%%%%%S#S%%%%%%%%%%%%%%%%%SSSS##S%#%%%%%%%%%%%%%%%%%%%S:................................. // %%%%%%%%%%%%%%%%%SS%%%%%%%%%%%%%%%%%%%#####%%#%%%%%%%%%%%%%%%%%%%S*................................. // %%%%%%%%%%%%%%%%%#S%%%%%%%%%%%%%%%%%%%S#S%%?S#%%%%%%%%%%%%%%%%%%%SS,................................ // %%%%%%%%%%%%%%%%S#S%%%%%%%%%%%%%%%%%%%%S#SS##S%%%%%%%%%%%%%%%%%%%%S;................................ // %%%%%%%%%%%%%%%%SS%%%%%%%%%%%%%%%%%%%%%%SS##S%%%%%%%%%%%%%%%%%%%%%S?................................ // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%SSS%%%%%%%%%%%%%%%%%%%%%S%,............................... // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#SS%%%%%%%%%%%%%%%%%%%%%%S:............................... // ...................... [Calling the blockchain to get provably fair results] ....................... /** * @title RaffleV2 * @notice This contract allows anyone to permissionlessly host raffles on LooksRare. * @author LooksRare protocol team (👀,💎) */ contract RaffleV2 is IRaffleV2, LowLevelWETH, LowLevelERC20Transfer, LowLevelERC721Transfer, LowLevelERC1155Transfer, VRFConsumerBaseV2, OwnableTwoSteps, PackableReentrancyGuard, Pausable, WinningEntrySearchLogicV2 { using Arrays for uint256[]; address private immutable WETH; uint256 private constant ONE_DAY = 86_400 seconds; uint256 private constant ONE_WEEK = 604_800 seconds; /** * @notice 100% in basis points. */ uint256 private constant ONE_HUNDRED_PERCENT_BP = 10_000; /** * @notice The raffles created. * @dev The key is the raffle ID. */ mapping(uint256 => Raffle) public raffles; /** * @notice The participants stats of the raffles. * @dev The key is the raffle ID and the nested key is the participant address. */ mapping(uint256 => mapping(address => ParticipantStats)) public rafflesParticipantsStats; /** * @notice It checks whether the currency is allowed. * @dev 0 is not allowed, 1 is allowed. */ mapping(address => uint256) public isCurrencyAllowed; /** * @notice The maximum number of prizes per raffle. * Each individual ERC-721 counts as one prize. * Each ETH/ERC-20/ERC-1155 with winnersCount > 1 counts as one prize. */ uint256 public constant MAXIMUM_NUMBER_OF_PRIZES_PER_RAFFLE = 200; /** * @notice The maximum number of winners per raffle. */ uint40 public constant MAXIMUM_NUMBER_OF_WINNERS_PER_RAFFLE = 200; /** * @notice The key hash of the Chainlink VRF. */ bytes32 private immutable KEY_HASH; /** * @notice The subscription ID of the Chainlink VRF. */ uint64 public immutable SUBSCRIPTION_ID; /** * @notice The Chainlink VRF coordinator. */ VRFCoordinatorV2Interface private immutable VRF_COORDINATOR; /** * @notice The randomness requests. * @dev The key is the request ID returned by Chainlink. */ mapping(uint256 => RandomnessRequest) public randomnessRequests; /** * @notice The maximum protocol fee in basis points, which is 25%. */ uint16 public constant MAXIMUM_PROTOCOL_FEE_BP = 2_500; /** * @notice The number of raffles created. * @dev In this smart contract, raffleId is an uint256 but its * max value can only be 2^80 - 1. Realistically we will still * not reach this number. */ uint80 public rafflesCount; /** * @notice The protocol fee recipient. */ address public protocolFeeRecipient; /** * @notice The protocol fee in basis points. */ uint16 public protocolFeeBp; /** * @notice The maximum number of pricing options per raffle. */ uint256 public constant MAXIMUM_PRICING_OPTIONS_PER_RAFFLE = 5; /** * @notice Transfer manager faciliates token transfers. */ ITransferManager private immutable transferManager; /** * @param _weth The WETH address * @param _keyHash Chainlink VRF key hash * @param _subscriptionId Chainlink VRF subscription ID * @param _vrfCoordinator Chainlink VRF coordinator address * @param _owner The owner of the contract * @param _protocolFeeRecipient The recipient of the protocol fees * @param _protocolFeeBp The protocol fee in basis points * @param _transferManager The transfer manager address */ constructor( address _weth, bytes32 _keyHash, uint64 _subscriptionId, address _vrfCoordinator, address _owner, address _protocolFeeRecipient, uint16 _protocolFeeBp, address _transferManager ) VRFConsumerBaseV2(_vrfCoordinator) OwnableTwoSteps(_owner) { _setProtocolFeeBp(_protocolFeeBp); _setProtocolFeeRecipient(_protocolFeeRecipient); WETH = _weth; KEY_HASH = _keyHash; VRF_COORDINATOR = VRFCoordinatorV2Interface(_vrfCoordinator); SUBSCRIPTION_ID = _subscriptionId; transferManager = ITransferManager(_transferManager); } /** * @inheritdoc IRaffleV2 */ function createRaffle(CreateRaffleCalldata calldata params) external payable nonReentrant whenNotPaused returns (uint256 raffleId) { uint40 cutoffTime = params.cutoffTime; if (_unsafeAdd(block.timestamp, ONE_DAY) > cutoffTime || cutoffTime > _unsafeAdd(block.timestamp, ONE_WEEK)) { revert InvalidCutoffTime(); } uint16 agreedProtocolFeeBp = params.protocolFeeBp; if (agreedProtocolFeeBp != protocolFeeBp) { revert InvalidProtocolFeeBp(); } address feeTokenAddress = params.feeTokenAddress; if (feeTokenAddress != address(0)) { _validateCurrency(feeTokenAddress); } uint256 prizesCount = params.prizes.length; if (prizesCount == 0 || prizesCount > MAXIMUM_NUMBER_OF_PRIZES_PER_RAFFLE) { revert InvalidPrizesCount(); } unchecked { raffleId = ++rafflesCount; } // The storage layout of a prize struct (3 slots) is as follows: // --------------------------------------------------------------------------------------------------------------------------------| // | prizeAddress (160 bits) | prizeTier (8 bits) | prizeType (8 bits) | cumulativeWinnersCount (40 bits) | winnersCount (40 bits) | // --------------------------------------------------------------------------------------------------------------------------------| // | prizeId (256 bits) | // --------------------------------------------------------------------------------------------------------------------------------| // | prizeAmount (256 bits) | // // The slot keccak256(raffleId, rafflesSlot) + 4 is used to store the length of the prizes array. // The slot keccak256(keccak256(raffleId, rafflesSlot) + 4) + i * 3 is used to store the prize at the i-th index // (x 3 because each prize consumes 3 slots). // // The assembly blocks are equivalent to `raffle.prizes.push(prize);` // // The primary benefit of using assembly is we only write the prizes length once instead of once per prize. uint256 raffleSlot; uint256 prizesLengthSlot; uint256 individualPrizeSlotOffset; assembly { mstore(0x00, raffleId) mstore(0x20, raffles.slot) raffleSlot := keccak256(0x00, 0x40) prizesLengthSlot := add(keccak256(0x00, 0x40), 4) mstore(0x00, prizesLengthSlot) individualPrizeSlotOffset := keccak256(0x00, 0x20) } uint256 expectedEthValue; uint40 cumulativeWinnersCount; { uint8 currentPrizeTier; for (uint256 i; i < prizesCount; ) { Prize memory prize = params.prizes[i]; uint8 prizeTier = prize.prizeTier; if (prizeTier < currentPrizeTier) { revert InvalidPrize(); } _validatePrize(prize); TokenType prizeType = prize.prizeType; uint40 winnersCount = prize.winnersCount; address prizeAddress = prize.prizeAddress; uint256 prizeId = prize.prizeId; uint256 prizeAmount = prize.prizeAmount; if (prizeType == TokenType.ERC721) { transferManager.transferItemERC721(prizeAddress, msg.sender, address(this), prizeId); } else if (prizeType == TokenType.ERC20) { transferManager.transferERC20(prizeAddress, msg.sender, address(this), prizeAmount * winnersCount); } else if (prizeType == TokenType.ETH) { expectedEthValue += (prizeAmount * winnersCount); } else { transferManager.transferItemERC1155( prizeAddress, msg.sender, address(this), prizeId, prizeAmount * winnersCount ); } cumulativeWinnersCount += winnersCount; currentPrizeTier = prizeTier; assembly { let prizeSlotOne := winnersCount prizeSlotOne := or(prizeSlotOne, shl(40, cumulativeWinnersCount)) prizeSlotOne := or(prizeSlotOne, shl(80, prizeType)) prizeSlotOne := or(prizeSlotOne, shl(88, prizeTier)) prizeSlotOne := or(prizeSlotOne, shl(96, prizeAddress)) let currentPrizeSlotOffset := add(individualPrizeSlotOffset, mul(i, 3)) sstore(currentPrizeSlotOffset, prizeSlotOne) sstore(add(currentPrizeSlotOffset, 1), prizeId) sstore(add(currentPrizeSlotOffset, 2), prizeAmount) } unchecked { ++i; } } assembly { sstore(prizesLengthSlot, prizesCount) } } _validateExpectedEthValueOrRefund(expectedEthValue); uint40 minimumEntries = params.minimumEntries; if (cumulativeWinnersCount > minimumEntries || cumulativeWinnersCount > MAXIMUM_NUMBER_OF_WINNERS_PER_RAFFLE) { revert InvalidWinnersCount(); } _validateAndSetPricingOptions(raffleId, minimumEntries, params.pricingOptions); bool isMinimumEntriesFixed = params.isMinimumEntriesFixed; uint40 maximumEntriesPerParticipant = params.maximumEntriesPerParticipant; // The storage layout of a raffle's first 2 slots is as follows: // ---------------------------------------------------------------------------------------------------------------------------------| // | drawnAt (40 bits) | cutoffTime (40 bits) | isMinimumEntriesFixed (8 bits) | status (8 bits) | owner (160 bits) | // ---------------------------------------------------------------------------------------------------------------------------------| // | agreedProtocolFeeBp (16 bits) | feeTokenAddress (160 bits) | maximumEntriesPerParticipant (40 bits) | minimumEntries (40 bits) | // ---------------------------------------------------------------------------------------------------------------------------------| // // And the slots for these values are calculated by the following formulas: // slot 1 = keccak256(raffleId, rafflesSlot) // slot 2 = keccak256(raffleId, rafflesSlot) + 1 // // This assembly block is equivalent to // raffle.owner = msg.sender; // raffle.status = RaffleStatus.Open; // raffle.isMinimumEntriesFixed = isMinimumEntriesFixed; // raffle.cutoffTime = cutoffTime; // raffle.minimumEntries = minimumEntries; // raffle.maximumEntriesPerParticipant = maximumEntriesPerParticipant; // raffle.protocolFeeBp = agreedProtocolFeeBp; // raffle.feeTokenAddress = feeTokenAddress; assembly { let raffleSlotOneValue := caller() raffleSlotOneValue := or(raffleSlotOneValue, shl(160, 1)) raffleSlotOneValue := or(raffleSlotOneValue, shl(168, isMinimumEntriesFixed)) raffleSlotOneValue := or(raffleSlotOneValue, shl(176, cutoffTime)) let raffleSlotTwoValue := minimumEntries raffleSlotTwoValue := or(raffleSlotTwoValue, shl(40, maximumEntriesPerParticipant)) raffleSlotTwoValue := or(raffleSlotTwoValue, shl(80, feeTokenAddress)) raffleSlotTwoValue := or(raffleSlotTwoValue, shl(240, agreedProtocolFeeBp)) sstore(raffleSlot, raffleSlotOneValue) sstore(add(raffleSlot, 1), raffleSlotTwoValue) } emit RaffleStatusUpdated(raffleId, RaffleStatus.Open); } /** * @dev This function is required in order for the contract to receive ERC-1155 tokens. */ function onERC1155Received( address, address, uint256, uint256, bytes calldata ) external pure returns (bytes4) { return this.onERC1155Received.selector; } /** * @inheritdoc IRaffleV2 * @notice If it is a delegated recipient, the amount paid should still be accrued to the payer. * If a raffle is cancelled, the payer should be refunded and not the recipient. */ function enterRaffles(EntryCalldata[] calldata entries) external payable nonReentrant whenNotPaused { (address feeTokenAddress, uint208 expectedValue) = _enterRaffles(entries); _chargeUser(feeTokenAddress, expectedValue); } /** * @param _requestId The ID of the request * @param _randomWords The random words returned by Chainlink */ function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal override { if (randomnessRequests[_requestId].exists) { uint256 raffleId = randomnessRequests[_requestId].raffleId; Raffle storage raffle = raffles[raffleId]; if (raffle.status == RaffleStatus.Drawing) { _setRaffleStatus(raffle, raffleId, RaffleStatus.RandomnessFulfilled); randomnessRequests[_requestId].randomWord = _randomWords[0]; } } } /** * @inheritdoc IRaffleV2 */ function selectWinners(uint256 requestId) external { RandomnessRequest memory randomnessRequest = randomnessRequests[requestId]; if (!randomnessRequest.exists) { revert RandomnessRequestDoesNotExist(); } uint256 raffleId = randomnessRequest.raffleId; Raffle storage raffle = raffles[raffleId]; _validateRaffleStatus(raffle, RaffleStatus.RandomnessFulfilled); _setRaffleStatus(raffle, raffleId, RaffleStatus.Drawn); Prize[] storage prizes = raffle.prizes; uint256 prizesCount = prizes.length; uint256 winnersCount = prizes[prizesCount - 1].cumulativeWinnersCount; Entry[] memory entries = raffle.entries; uint256 entriesCount = entries.length; uint256[] memory currentEntryIndexArray = new uint256[](entriesCount); for (uint256 i; i < entriesCount; ) { currentEntryIndexArray[i] = entries[i].currentEntryIndex; unchecked { ++i; } } uint256 currentEntryIndex = uint256(currentEntryIndexArray[entriesCount - 1]); uint256[] memory winningEntriesBitmap = new uint256[]((currentEntryIndex >> 8) + 1); uint256[] memory cumulativeWinnersCountArray = new uint256[](prizesCount); for (uint256 i; i < prizesCount; ) { cumulativeWinnersCountArray[i] = prizes[i].cumulativeWinnersCount; unchecked { ++i; } } uint256 randomWord = randomnessRequest.randomWord; uint256 winningEntry; // The storage layout of a winner slot is as follows: // ------------------------------------------------------------------------------------------------------------| // | unused (40 bits) | entryIndex (40 bits) | prizeIndex (8 bits) | claimed (8 bits) | participant (160 bits) | // ------------------------------------------------------------------------------------------------------------| // // The slot keccak256(raffleId, rafflesSlot) + 6 is used to store the length of the winners array. // The slot keccak256(keccak256(raffleId, rafflesSlot) + 6) + i is used to store the winner at the i-th index. // // The assembly blocks are equivalent to // raffle.winners.push( // Winner({ // participant: entries[currentEntryIndexArray.findUpperBound(winningEntry)].participant, // claimed: false, // prizeIndex: uint8(cumulativeWinnersCountArray.findUpperBound(_unsafeAdd(i, 1))), // entryIndex: uint40(winningEntry) // }) // ); // // The primary benefit of using assembly is we only write the winners length once instead of once per winner. uint256 winnersLengthSlot; uint256 individualWinnerSlotOffset; assembly { mstore(0x00, raffleId) mstore(0x20, raffles.slot) winnersLengthSlot := add(keccak256(0x00, 0x40), 6) mstore(0x00, winnersLengthSlot) individualWinnerSlotOffset := keccak256(0x00, 0x20) } for (uint256 i; i < winnersCount; ) { (randomWord, winningEntry, winningEntriesBitmap) = _searchForWinningEntryUntilThereIsNotADuplicate( randomWord, currentEntryIndex, winningEntriesBitmap ); address participant = entries[currentEntryIndexArray.findUpperBound(winningEntry)].participant; uint256 prizeIndex = cumulativeWinnersCountArray.findUpperBound(_unsafeAdd(i, 1)); assembly { let winnerSlotValue := participant winnerSlotValue := or(winnerSlotValue, shl(168, prizeIndex)) winnerSlotValue := or(winnerSlotValue, shl(176, winningEntry)) sstore(add(individualWinnerSlotOffset, i), winnerSlotValue) } randomWord = uint256(keccak256(abi.encodePacked(randomWord))); unchecked { ++i; } } assembly { sstore(winnersLengthSlot, winnersCount) } } /** * @inheritdoc IRaffleV2 */ function claimPrize(uint256 raffleId, uint256 winnerIndex) external nonReentrant whenNotPaused { Raffle storage raffle = raffles[raffleId]; if (raffle.status != RaffleStatus.Drawn) { _validateRaffleStatus(raffle, RaffleStatus.Complete); } Winner[] storage winners = raffle.winners; if (winnerIndex >= winners.length) { revert InvalidIndex(); } Winner storage winner = winners[winnerIndex]; if (winner.claimed) { revert NothingToClaim(); } _validateCaller(winner.participant); winner.claimed = true; _transferPrize({prize: raffle.prizes[winner.prizeIndex], recipient: msg.sender, multiplier: 1}); emit PrizeClaimed(raffleId, winnerIndex); } /** * @inheritdoc IRaffleV2 */ function claimPrizes(ClaimPrizesCalldata[] calldata claimPrizesCalldata) external nonReentrant whenNotPaused { TransferAccumulator memory transferAccumulator; for (uint256 i; i < claimPrizesCalldata.length; ) { ClaimPrizesCalldata calldata perRaffleClaimPrizesCalldata = claimPrizesCalldata[i]; uint256 raffleId = perRaffleClaimPrizesCalldata.raffleId; Raffle storage raffle = raffles[raffleId]; if (raffle.status != RaffleStatus.Drawn) { _validateRaffleStatus(raffle, RaffleStatus.Complete); } Winner[] storage winners = raffle.winners; uint256[] calldata winnerIndices = perRaffleClaimPrizesCalldata.winnerIndices; uint256 winnersCount = winners.length; uint256 claimsCount = winnerIndices.length; for (uint256 j; j < claimsCount; ) { uint256 winnerIndex = winnerIndices[j]; if (winnerIndex >= winnersCount) { revert InvalidIndex(); } Winner storage winner = winners[winnerIndex]; if (winner.claimed) { revert NothingToClaim(); } _validateCaller(winner.participant); winner.claimed = true; Prize storage prize = raffle.prizes[winner.prizeIndex]; if (prize.prizeType > TokenType.ERC1155) { address prizeAddress = prize.prizeAddress; if (prizeAddress == transferAccumulator.tokenAddress) { transferAccumulator.amount += prize.prizeAmount; } else { if (transferAccumulator.amount != 0) { _transferFungibleTokens(transferAccumulator); } transferAccumulator.tokenAddress = prizeAddress; transferAccumulator.amount = prize.prizeAmount; } } else { _transferPrize({prize: prize, recipient: msg.sender, multiplier: 1}); } unchecked { ++j; } } emit PrizesClaimed(raffleId, winnerIndices); unchecked { ++i; } } if (transferAccumulator.amount != 0) { _transferFungibleTokens(transferAccumulator); } } /** * @inheritdoc IRaffleV2 */ function claimFees(uint256 raffleId) external nonReentrant whenNotPaused { Raffle storage raffle = raffles[raffleId]; _validateRaffleStatus(raffle, RaffleStatus.Drawn); address raffleOwner = raffle.owner; if (msg.sender != raffleOwner) { _validateCaller(owner); } uint208 claimableFees = raffle.claimableFees; uint208 protocolFees = (claimableFees * uint208(raffle.protocolFeeBp)) / uint208(ONE_HUNDRED_PERCENT_BP); unchecked { claimableFees -= protocolFees; } _setRaffleStatus(raffle, raffleId, RaffleStatus.Complete); raffle.claimableFees = 0; address feeTokenAddress = raffle.feeTokenAddress; _transferFungibleTokens(feeTokenAddress, raffleOwner, claimableFees); if (protocolFees != 0) { _transferFungibleTokens(feeTokenAddress, protocolFeeRecipient, protocolFees); } emit FeesClaimed(raffleId, claimableFees); } /** * @inheritdoc IRaffleV2 */ function cancel(uint256 raffleId) external nonReentrant whenNotPaused { Raffle storage raffle = raffles[raffleId]; _validateRafflePostCutoffTimeStatusTransferability(raffle); if (block.timestamp < raffle.cutoffTime + 1 hours) { _validateCaller(raffle.owner); } _setRaffleStatus(raffle, raffleId, RaffleStatus.Refundable); } /** * @inheritdoc IRaffleV2 * @notice A raffle cannot be drawn if there are less entries than prizes. */ function drawWinners(uint256 raffleId) external nonReentrant whenNotPaused { Raffle storage raffle = raffles[raffleId]; Entry[] storage entries = raffle.entries; uint256 entriesCount = entries.length; if (entriesCount == 0) { revert NotEnoughEntries(); } Prize[] storage prizes = raffle.prizes; if (prizes[prizes.length - 1].cumulativeWinnersCount > entries[entriesCount - 1].currentEntryIndex + 1) { revert NotEnoughEntries(); } _validateRafflePostCutoffTimeStatusTransferability(raffle); _validateCaller(raffle.owner); _drawWinners(raffleId, raffle); } /** * @inheritdoc IRaffleV2 */ function cancelAfterRandomnessRequest(uint256 raffleId) external nonReentrant whenNotPaused { Raffle storage raffle = raffles[raffleId]; _validateRaffleStatus(raffle, RaffleStatus.Drawing); if (block.timestamp < raffle.drawnAt + ONE_DAY) { revert DrawExpirationTimeNotReached(); } _setRaffleStatus(raffle, raffleId, RaffleStatus.Refundable); } /** * @inheritdoc IRaffleV2 */ function withdrawPrizes(uint256 raffleId) external nonReentrant whenNotPaused { Raffle storage raffle = raffles[raffleId]; _validateRaffleStatus(raffle, RaffleStatus.Refundable); _setRaffleStatus(raffle, raffleId, RaffleStatus.Cancelled); uint256 prizesCount = raffle.prizes.length; address raffleOwner = raffle.owner; for (uint256 i; i < prizesCount; ) { Prize storage prize = raffle.prizes[i]; _transferPrize({prize: prize, recipient: raffleOwner, multiplier: uint256(prize.winnersCount)}); unchecked { ++i; } } } /** * @inheritdoc IRaffleV2 * @dev Refundable and Cancelled are the only statuses that allow refunds. */ function claimRefund(uint256[] calldata raffleIds) external nonReentrant whenNotPaused { (address feeTokenAddress, uint208 refundAmount) = _claimRefund(raffleIds); _transferFungibleTokens(feeTokenAddress, msg.sender, refundAmount); } /** * @inheritdoc IRaffleV2 * @notice The fee token address for all the raffles involved must be the same. * @dev Refundable and Cancelled are the only statuses that allow refunds. */ function rollover(uint256[] calldata refundableRaffleIds, EntryCalldata[] calldata entries) external payable nonReentrant whenNotPaused { (address refundFeeTokenAddress, uint208 rolloverAmount) = _claimRefund(refundableRaffleIds); (address enterRafflesFeeTokenAddress, uint208 expectedValue) = _enterRaffles(entries); if (refundFeeTokenAddress != enterRafflesFeeTokenAddress) { revert InvalidCurrency(); } if (rolloverAmount > expectedValue) { _transferFungibleTokens(refundFeeTokenAddress, msg.sender, _unsafeSubtract(rolloverAmount, expectedValue)); } else if (rolloverAmount < expectedValue) { _chargeUser(refundFeeTokenAddress, _unsafeSubtract(expectedValue, rolloverAmount)); } } /** * @inheritdoc IRaffleV2 */ function setProtocolFeeRecipient(address _protocolFeeRecipient) external onlyOwner { _setProtocolFeeRecipient(_protocolFeeRecipient); } /** * @inheritdoc IRaffleV2 */ function setProtocolFeeBp(uint16 _protocolFeeBp) external onlyOwner { _setProtocolFeeBp(_protocolFeeBp); } /** * @inheritdoc IRaffleV2 */ function updateCurrenciesStatus(address[] calldata currencies, bool isAllowed) external onlyOwner { uint256 count = currencies.length; for (uint256 i; i < count; ) { isCurrencyAllowed[currencies[i]] = (isAllowed ? 1 : 0); unchecked { ++i; } } emit CurrenciesStatusUpdated(currencies, isAllowed); } /** * @inheritdoc IRaffleV2 */ function togglePaused() external onlyOwner { paused() ? _unpause() : _pause(); } /** * @inheritdoc IRaffleV2 */ function getWinners(uint256 raffleId) external view returns (Winner[] memory winners) { winners = raffles[raffleId].winners; } /** * @inheritdoc IRaffleV2 */ function getPrizes(uint256 raffleId) external view returns (Prize[] memory prizes) { prizes = raffles[raffleId].prizes; } /** * @inheritdoc IRaffleV2 */ function getEntries(uint256 raffleId) external view returns (Entry[] memory entries) { entries = raffles[raffleId].entries; } /** * @inheritdoc IRaffleV2 */ function getPricingOptions(uint256 raffleId) external view returns (PricingOption[] memory pricingOptions) { pricingOptions = raffles[raffleId].pricingOptions; } /** * @param _protocolFeeRecipient The new protocol fee recipient address */ function _setProtocolFeeRecipient(address _protocolFeeRecipient) private { if (_protocolFeeRecipient == address(0)) { revert InvalidProtocolFeeRecipient(); } protocolFeeRecipient = _protocolFeeRecipient; emit ProtocolFeeRecipientUpdated(_protocolFeeRecipient); } /** * @param _protocolFeeBp The new protocol fee in basis points */ function _setProtocolFeeBp(uint16 _protocolFeeBp) private { if (_protocolFeeBp > MAXIMUM_PROTOCOL_FEE_BP) { revert InvalidProtocolFeeBp(); } protocolFeeBp = _protocolFeeBp; emit ProtocolFeeBpUpdated(_protocolFeeBp); } /** * @param raffleId The ID of the raffle. * @param pricingOptions The pricing options for the raffle. */ function _validateAndSetPricingOptions( uint256 raffleId, uint40 minimumEntries, PricingOption[] calldata pricingOptions ) private { uint256 count = pricingOptions.length; if (count == 0 || count > MAXIMUM_PRICING_OPTIONS_PER_RAFFLE) { revert InvalidPricingOptionsCount(); } uint40 lowestEntriesCount = pricingOptions[0].entriesCount; // The storage layout of a pricing option slot is as follows: // ---------------------------------------------------------------| // | unused (8 bits) | price (208 bits) | entries count (40 bits) | // ---------------------------------------------------------------| // // The slot keccak256(raffleId, rafflesSlot) + 3 is used to store the length of the pricing options array. // The slot keccak256(keccak256(raffleId, rafflesSlot) + 3) + i is used to store the pricing option at the i-th index. // // The assembly blocks are equivalent to `raffles[raffleId].pricingOptions.push(pricingOption);` // // The primary benefit of using assembly is we only write the pricing options length once instead of once per pricing option. uint256 pricingOptionsLengthSlot; uint256 individualPricingOptionSlotOffset; assembly { mstore(0x00, raffleId) mstore(0x20, raffles.slot) pricingOptionsLengthSlot := add(keccak256(0x00, 0x40), 3) mstore(0x00, pricingOptionsLengthSlot) individualPricingOptionSlotOffset := keccak256(0x00, 0x20) } for (uint256 i; i < count; ) { PricingOption memory pricingOption = pricingOptions[i]; uint40 entriesCount = pricingOption.entriesCount; uint208 price = pricingOption.price; if (i == 0) { if (minimumEntries % entriesCount != 0 || price == 0) { revert InvalidPricingOption(); } } else { PricingOption memory lastPricingOption = pricingOptions[_unsafeSubtract(i, 1)]; uint208 lastPrice = lastPricingOption.price; uint40 lastEntriesCount = lastPricingOption.entriesCount; if ( entriesCount % lowestEntriesCount != 0 || price % entriesCount != 0 || entriesCount <= lastEntriesCount || price <= lastPrice || price / entriesCount > lastPrice / lastEntriesCount ) { revert InvalidPricingOption(); } } assembly { let pricingOptionValue := entriesCount pricingOptionValue := or(pricingOptionValue, shl(40, price)) sstore(add(individualPricingOptionSlotOffset, i), pricingOptionValue) } unchecked { ++i; } } assembly { sstore(pricingOptionsLengthSlot, count) } } /** * @param prize The prize. */ function _validatePrize(Prize memory prize) private view { TokenType prizeType = prize.prizeType; if (prizeType == TokenType.ERC721) { if (prize.prizeAmount != 1 || prize.winnersCount != 1) { revert InvalidPrize(); } } else { if (prizeType == TokenType.ERC20) { _validateCurrency(prize.prizeAddress); } if (prize.prizeAmount == 0 || prize.winnersCount == 0) { revert InvalidPrize(); } } } /** * @param prize The prize to transfer. * @param recipient The recipient of the prize. * @param multiplier The multiplier to apply to the prize amount. */ function _transferPrize( Prize storage prize, address recipient, uint256 multiplier ) private { TokenType prizeType = prize.prizeType; address prizeAddress = prize.prizeAddress; if (prizeType == TokenType.ERC721) { _executeERC721TransferFrom(prizeAddress, address(this), recipient, prize.prizeId); } else if (prizeType == TokenType.ERC1155) { _executeERC1155SafeTransferFrom( prizeAddress, address(this), recipient, prize.prizeId, prize.prizeAmount * multiplier ); } else { _transferFungibleTokens(prizeAddress, recipient, prize.prizeAmount * multiplier); } } /** * @param currency The currency to transfer. * @param recipient The recipient of the currency. * @param amount The amount of currency to transfer. */ function _transferFungibleTokens( address currency, address recipient, uint256 amount ) private { if (currency == address(0)) { _transferETHAndWrapIfFailWithGasLimit(WETH, recipient, amount, gasleft()); } else { _executeERC20DirectTransfer(currency, recipient, amount); } } /** * @param transferAccumulator The transfer accumulator. */ function _transferFungibleTokens(TransferAccumulator memory transferAccumulator) private { _transferFungibleTokens(transferAccumulator.tokenAddress, msg.sender, transferAccumulator.amount); } /** * @param raffleId The ID of the raffle to draw winners for. * @param raffle The raffle to draw winners for. */ function _drawWinners(uint256 raffleId, Raffle storage raffle) private { _setRaffleStatus(raffle, raffleId, RaffleStatus.Drawing); raffle.drawnAt = uint40(block.timestamp); uint256 requestId = VRF_COORDINATOR.requestRandomWords({ keyHash: KEY_HASH, subId: SUBSCRIPTION_ID, minimumRequestConfirmations: uint16(3), callbackGasLimit: uint32(500_000), numWords: uint32(1) }); if (randomnessRequests[requestId].exists) { revert RandomnessRequestAlreadyExists(); } randomnessRequests[requestId].exists = true; randomnessRequests[requestId].raffleId = uint80(raffleId); emit RandomnessRequested(raffleId, requestId); } /** * @param raffle The raffle to check the status of. * @param status The expected status of the raffle */ function _validateRaffleStatus(Raffle storage raffle, RaffleStatus status) private view { if (raffle.status != status) { revert InvalidStatus(); } } /** * @param entries The entries to enter. */ function _enterRaffles(EntryCalldata[] calldata entries) private returns (address feeTokenAddress, uint208 expectedValue) { uint256 count = entries.length; for (uint256 i; i < count; ) { EntryCalldata calldata entry = entries[i]; address recipient = entry.recipient == address(0) ? msg.sender : entry.recipient; uint256 raffleId = entry.raffleId; Raffle storage raffle = raffles[raffleId]; if (i == 0) { feeTokenAddress = raffle.feeTokenAddress; } else if (raffle.feeTokenAddress != feeTokenAddress) { revert InvalidCurrency(); } if (entry.pricingOptionIndex >= raffle.pricingOptions.length) { revert InvalidIndex(); } _validateRaffleStatus(raffle, RaffleStatus.Open); if (block.timestamp >= raffle.cutoffTime) { revert CutoffTimeReached(); } uint40 entriesCount; uint208 price; { PricingOption memory pricingOption = raffle.pricingOptions[entry.pricingOptionIndex]; uint40 multiplier = entry.count; if (multiplier == 0) { revert InvalidCount(); } entriesCount = pricingOption.entriesCount * multiplier; price = pricingOption.price * multiplier; uint40 newParticipantEntriesCount = rafflesParticipantsStats[raffleId][recipient].entriesCount + entriesCount; if (newParticipantEntriesCount > raffle.maximumEntriesPerParticipant) { revert MaximumEntriesPerParticipantReached(); } rafflesParticipantsStats[raffleId][recipient].entriesCount = newParticipantEntriesCount; } expectedValue += price; uint256 raffleEntriesCount = raffle.entries.length; uint40 currentEntryIndex; if (raffleEntriesCount == 0) { currentEntryIndex = uint40(_unsafeSubtract(entriesCount, 1)); } else { currentEntryIndex = raffle.entries[_unsafeSubtract(raffleEntriesCount, 1)].currentEntryIndex + entriesCount; } if (raffle.isMinimumEntriesFixed) { if (currentEntryIndex >= raffle.minimumEntries) { revert MaximumEntriesReached(); } } _pushEntry(raffle, currentEntryIndex, recipient); raffle.claimableFees += price; rafflesParticipantsStats[raffleId][msg.sender].amountPaid += price; emit EntrySold(raffleId, msg.sender, recipient, entriesCount, price); if (currentEntryIndex >= _unsafeSubtract(raffle.minimumEntries, 1)) { _drawWinners(raffleId, raffle); } unchecked { ++i; } } } /** * @param feeTokenAddress The address of the token to charge the fee in. * @param expectedValue The expected value of the fee. */ function _chargeUser(address feeTokenAddress, uint256 expectedValue) private { if (feeTokenAddress == address(0)) { _validateExpectedEthValueOrRefund(expectedValue); } else { transferManager.transferERC20(feeTokenAddress, msg.sender, address(this), expectedValue); } } /** * @param raffleIds The IDs of the raffles to claim refunds for. */ function _claimRefund(uint256[] calldata raffleIds) private returns (address feeTokenAddress, uint208 refundAmount) { uint256 count = raffleIds.length; for (uint256 i; i < count; ) { uint256 raffleId = raffleIds[i]; Raffle storage raffle = raffles[raffleId]; if (raffle.status < RaffleStatus.Refundable) { revert InvalidStatus(); } ParticipantStats storage stats = rafflesParticipantsStats[raffleId][msg.sender]; uint208 amountPaid = stats.amountPaid; if (stats.refunded || amountPaid == 0) { revert NothingToClaim(); } if (i == 0) { feeTokenAddress = raffle.feeTokenAddress; } else if (feeTokenAddress != raffle.feeTokenAddress) { revert InvalidCurrency(); } stats.refunded = true; refundAmount += amountPaid; emit EntryRefunded(raffleId, msg.sender, amountPaid); unchecked { ++i; } } } /** * @param caller The expected caller. */ function _validateCaller(address caller) private view { if (msg.sender != caller) { revert InvalidCaller(); } } /** * @param currency The currency to validate. */ function _validateCurrency(address currency) private view { if (isCurrencyAllowed[currency] != 1) { revert InvalidCurrency(); } } /** * @param expectedEthValue The expected ETH value to be sent by the caller. */ function _validateExpectedEthValueOrRefund(uint256 expectedEthValue) private { if (expectedEthValue > msg.value) { revert InsufficientNativeTokensSupplied(); } else if (msg.value > expectedEthValue) { _transferETHAndWrapIfFailWithGasLimit( WETH, msg.sender, _unsafeSubtract(msg.value, expectedEthValue), gasleft() ); } } /** * @param raffle The raffle to validate. */ function _validateRafflePostCutoffTimeStatusTransferability(Raffle storage raffle) private view { _validateRaffleStatus(raffle, RaffleStatus.Open); if (raffle.cutoffTime > block.timestamp) { revert CutoffTimeNotReached(); } } /** * @param raffle The raffle to set the status of. * @param raffleId The ID of the raffle to set the status of. * @param status The status to set. */ function _setRaffleStatus( Raffle storage raffle, uint256 raffleId, RaffleStatus status ) private { raffle.status = status; emit RaffleStatusUpdated(raffleId, status); } /** * @param raffle The raffle to add the entry to. * @param currentEntryIndex The cumulative number of entries in the raffle minus one. * @param recipient The recipient of the entry. */ function _pushEntry( Raffle storage raffle, uint40 currentEntryIndex, address recipient ) private { raffle.entries.push(Entry({currentEntryIndex: currentEntryIndex, participant: recipient})); } /** * Unsafe math functions. */ function _unsafeAdd(uint256 a, uint256 b) private pure returns (uint256) { unchecked { return a + b; } } function _unsafeSubtract(uint256 a, uint256 b) private pure returns (uint256) { unchecked { return a - b; } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; // Interfaces import {IWETH} from "../interfaces/generic/IWETH.sol"; /** * @title LowLevelWETH * @notice This contract contains a function to transfer ETH with an option to wrap to WETH. * If the ETH transfer fails within a gas limit, the amount in ETH is wrapped to WETH and then transferred. * @author LooksRare protocol team (👀,💎) */ contract LowLevelWETH { /** * @notice It transfers ETH to a recipient with a specified gas limit. * If the original transfers fails, it wraps to WETH and transfers the WETH to recipient. * @param _WETH WETH address * @param _to Recipient address * @param _amount Amount to transfer * @param _gasLimit Gas limit to perform the ETH transfer */ function _transferETHAndWrapIfFailWithGasLimit( address _WETH, address _to, uint256 _amount, uint256 _gasLimit ) internal { bool status; assembly { status := call(_gasLimit, _to, _amount, 0, 0, 0, 0) } if (!status) { IWETH(_WETH).deposit{value: _amount}(); IWETH(_WETH).transfer(_to, _amount); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; // Interfaces import {IERC20} from "../interfaces/generic/IERC20.sol"; // Errors import {ERC20TransferFail, ERC20TransferFromFail} from "../errors/LowLevelErrors.sol"; import {NotAContract} from "../errors/GenericErrors.sol"; /** * @title LowLevelERC20Transfer * @notice This contract contains low-level calls to transfer ERC20 tokens. * @author LooksRare protocol team (👀,💎) */ contract LowLevelERC20Transfer { /** * @notice Execute ERC20 transferFrom * @param currency Currency address * @param from Sender address * @param to Recipient address * @param amount Amount to transfer */ function _executeERC20TransferFrom(address currency, address from, address to, uint256 amount) internal { if (currency.code.length == 0) { revert NotAContract(); } (bool status, bytes memory data) = currency.call(abi.encodeCall(IERC20.transferFrom, (from, to, amount))); if (!status) { revert ERC20TransferFromFail(); } if (data.length > 0) { if (!abi.decode(data, (bool))) { revert ERC20TransferFromFail(); } } } /** * @notice Execute ERC20 (direct) transfer * @param currency Currency address * @param to Recipient address * @param amount Amount to transfer */ function _executeERC20DirectTransfer(address currency, address to, uint256 amount) internal { if (currency.code.length == 0) { revert NotAContract(); } (bool status, bytes memory data) = currency.call(abi.encodeCall(IERC20.transfer, (to, amount))); if (!status) { revert ERC20TransferFail(); } if (data.length > 0) { if (!abi.decode(data, (bool))) { revert ERC20TransferFail(); } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; // Interfaces import {IERC721} from "../interfaces/generic/IERC721.sol"; // Errors import {ERC721TransferFromFail} from "../errors/LowLevelErrors.sol"; import {NotAContract} from "../errors/GenericErrors.sol"; /** * @title LowLevelERC721Transfer * @notice This contract contains low-level calls to transfer ERC721 tokens. * @author LooksRare protocol team (👀,💎) */ contract LowLevelERC721Transfer { /** * @notice Execute ERC721 transferFrom * @param collection Address of the collection * @param from Address of the sender * @param to Address of the recipient * @param tokenId tokenId to transfer */ function _executeERC721TransferFrom(address collection, address from, address to, uint256 tokenId) internal { if (collection.code.length == 0) { revert NotAContract(); } (bool status, ) = collection.call(abi.encodeCall(IERC721.transferFrom, (from, to, tokenId))); if (!status) { revert ERC721TransferFromFail(); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; // Interfaces import {IERC1155} from "../interfaces/generic/IERC1155.sol"; // Errors import {ERC1155SafeTransferFromFail, ERC1155SafeBatchTransferFromFail} from "../errors/LowLevelErrors.sol"; import {NotAContract} from "../errors/GenericErrors.sol"; /** * @title LowLevelERC1155Transfer * @notice This contract contains low-level calls to transfer ERC1155 tokens. * @author LooksRare protocol team (👀,💎) */ contract LowLevelERC1155Transfer { /** * @notice Execute ERC1155 safeTransferFrom * @param collection Address of the collection * @param from Address of the sender * @param to Address of the recipient * @param tokenId tokenId to transfer * @param amount Amount to transfer */ function _executeERC1155SafeTransferFrom( address collection, address from, address to, uint256 tokenId, uint256 amount ) internal { if (collection.code.length == 0) { revert NotAContract(); } (bool status, ) = collection.call(abi.encodeCall(IERC1155.safeTransferFrom, (from, to, tokenId, amount, ""))); if (!status) { revert ERC1155SafeTransferFromFail(); } } /** * @notice Execute ERC1155 safeBatchTransferFrom * @param collection Address of the collection * @param from Address of the sender * @param to Address of the recipient * @param tokenIds Array of tokenIds to transfer * @param amounts Array of amounts to transfer */ function _executeERC1155SafeBatchTransferFrom( address collection, address from, address to, uint256[] calldata tokenIds, uint256[] calldata amounts ) internal { if (collection.code.length == 0) { revert NotAContract(); } (bool status, ) = collection.call( abi.encodeCall(IERC1155.safeBatchTransferFrom, (from, to, tokenIds, amounts, "")) ); if (!status) { revert ERC1155SafeBatchTransferFromFail(); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; // Interfaces import {IOwnableTwoSteps} from "./interfaces/IOwnableTwoSteps.sol"; /** * @title OwnableTwoSteps * @notice This contract offers transfer of ownership in two steps with potential owner * having to confirm the transaction to become the owner. * Renouncement of the ownership is also a two-step process since the next potential owner is the address(0). * @author LooksRare protocol team (👀,💎) */ abstract contract OwnableTwoSteps is IOwnableTwoSteps { /** * @notice Address of the current owner. */ address public owner; /** * @notice Address of the potential owner. */ address public potentialOwner; /** * @notice Ownership status. */ Status public ownershipStatus; /** * @notice Modifier to wrap functions for contracts that inherit this contract. */ modifier onlyOwner() { _onlyOwner(); _; } /** * @notice Constructor * @param _owner The contract's owner */ constructor(address _owner) { owner = _owner; emit NewOwner(_owner); } /** * @notice This function is used to cancel the ownership transfer. * @dev This function can be used for both cancelling a transfer to a new owner and * cancelling the renouncement of the ownership. */ function cancelOwnershipTransfer() external onlyOwner { Status _ownershipStatus = ownershipStatus; if (_ownershipStatus == Status.NoOngoingTransfer) { revert NoOngoingTransferInProgress(); } if (_ownershipStatus == Status.TransferInProgress) { delete potentialOwner; } delete ownershipStatus; emit CancelOwnershipTransfer(); } /** * @notice This function is used to confirm the ownership renouncement. */ function confirmOwnershipRenouncement() external onlyOwner { if (ownershipStatus != Status.RenouncementInProgress) { revert RenouncementNotInProgress(); } delete owner; delete ownershipStatus; emit NewOwner(address(0)); } /** * @notice This function is used to confirm the ownership transfer. * @dev This function can only be called by the current potential owner. */ function confirmOwnershipTransfer() external { if (ownershipStatus != Status.TransferInProgress) { revert TransferNotInProgress(); } if (msg.sender != potentialOwner) { revert WrongPotentialOwner(); } owner = msg.sender; delete ownershipStatus; delete potentialOwner; emit NewOwner(msg.sender); } /** * @notice This function is used to initiate the transfer of ownership to a new owner. * @param newPotentialOwner New potential owner address */ function initiateOwnershipTransfer(address newPotentialOwner) external onlyOwner { if (ownershipStatus != Status.NoOngoingTransfer) { revert TransferAlreadyInProgress(); } ownershipStatus = Status.TransferInProgress; potentialOwner = newPotentialOwner; /** * @dev This function can only be called by the owner, so msg.sender is the owner. * We don't have to SLOAD the owner again. */ emit InitiateOwnershipTransfer(msg.sender, newPotentialOwner); } /** * @notice This function is used to initiate the ownership renouncement. */ function initiateOwnershipRenouncement() external onlyOwner { if (ownershipStatus != Status.NoOngoingTransfer) { revert TransferAlreadyInProgress(); } ownershipStatus = Status.RenouncementInProgress; emit InitiateOwnershipRenouncement(); } function _onlyOwner() private view { if (msg.sender != owner) revert NotOwner(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; // Interfaces import {IReentrancyGuard} from "./interfaces/IReentrancyGuard.sol"; /** * @title PackableReentrancyGuard * @notice This contract protects against reentrancy attacks. * It is adjusted from OpenZeppelin. * The only difference between this contract and ReentrancyGuard * is that _status is uint8 instead of uint256 so that it can be * packed with other contracts' storage variables. * @author LooksRare protocol team (👀,💎) */ abstract contract PackableReentrancyGuard is IReentrancyGuard { uint8 private _status; /** * @notice Modifier to wrap functions to prevent reentrancy calls. */ modifier nonReentrant() { if (_status == 2) { revert ReentrancyFail(); } _status = 2; _; _status = 1; } constructor() { _status = 1; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; /** * @title Pausable * @notice This contract makes it possible to pause the contract. * It is adjusted from OpenZeppelin. * @author LooksRare protocol team (👀,💎) */ abstract contract Pausable { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); error IsPaused(); error NotPaused(); bool private _paused; /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { _requireNotPaused(); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { _requirePaused(); _; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Throws if the contract is paused. */ function _requireNotPaused() internal view virtual { if (paused()) { revert IsPaused(); } } /** * @dev Throws if the contract is not paused. */ function _requirePaused() internal view virtual { if (!paused()) { revert NotPaused(); } } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(msg.sender); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(msg.sender); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.20; // Enums import {TokenType} from "../enums/TokenType.sol"; /** * @title ITransferManager * @author LooksRare protocol team (👀,💎) */ interface ITransferManager { /** * @notice This struct is only used for transferBatchItemsAcrossCollections. * @param tokenAddress Token address * @param tokenType 0 for ERC721, 1 for ERC1155 * @param itemIds Array of item ids to transfer * @param amounts Array of amounts to transfer */ struct BatchTransferItem { address tokenAddress; TokenType tokenType; uint256[] itemIds; uint256[] amounts; } /** * @notice It is emitted if operators' approvals to transfer NFTs are granted by a user. * @param user Address of the user * @param operators Array of operator addresses */ event ApprovalsGranted(address user, address[] operators); /** * @notice It is emitted if operators' approvals to transfer NFTs are revoked by a user. * @param user Address of the user * @param operators Array of operator addresses */ event ApprovalsRemoved(address user, address[] operators); /** * @notice It is emitted if a new operator is added to the global allowlist. * @param operator Operator address */ event OperatorAllowed(address operator); /** * @notice It is emitted if an operator is removed from the global allowlist. * @param operator Operator address */ event OperatorRemoved(address operator); /** * @notice It is returned if the operator to approve has already been approved by the user. */ error OperatorAlreadyApprovedByUser(); /** * @notice It is returned if the operator to revoke has not been previously approved by the user. */ error OperatorNotApprovedByUser(); /** * @notice It is returned if the transfer caller is already allowed by the owner. * @dev This error can only be returned for owner operations. */ error OperatorAlreadyAllowed(); /** * @notice It is returned if the operator to approve is not in the global allowlist defined by the owner. * @dev This error can be returned if the user tries to grant approval to an operator address not in the * allowlist or if the owner tries to remove the operator from the global allowlist. */ error OperatorNotAllowed(); /** * @notice It is returned if the transfer caller is invalid. * For a transfer called to be valid, the operator must be in the global allowlist and * approved by the 'from' user. */ error TransferCallerInvalid(); /** * @notice This function transfers ERC20 tokens. * @param tokenAddress Token address * @param from Sender address * @param to Recipient address * @param amount amount */ function transferERC20( address tokenAddress, address from, address to, uint256 amount ) external; /** * @notice This function transfers a single item for a single ERC721 collection. * @param tokenAddress Token address * @param from Sender address * @param to Recipient address * @param itemId Item ID */ function transferItemERC721( address tokenAddress, address from, address to, uint256 itemId ) external; /** * @notice This function transfers items for a single ERC721 collection. * @param tokenAddress Token address * @param from Sender address * @param to Recipient address * @param itemIds Array of itemIds * @param amounts Array of amounts */ function transferItemsERC721( address tokenAddress, address from, address to, uint256[] calldata itemIds, uint256[] calldata amounts ) external; /** * @notice This function transfers a single item for a single ERC1155 collection. * @param tokenAddress Token address * @param from Sender address * @param to Recipient address * @param itemId Item ID * @param amount Amount */ function transferItemERC1155( address tokenAddress, address from, address to, uint256 itemId, uint256 amount ) external; /** * @notice This function transfers items for a single ERC1155 collection. * @param tokenAddress Token address * @param from Sender address * @param to Recipient address * @param itemIds Array of itemIds * @param amounts Array of amounts * @dev It does not allow batch transferring if from = msg.sender since native function should be used. */ function transferItemsERC1155( address tokenAddress, address from, address to, uint256[] calldata itemIds, uint256[] calldata amounts ) external; /** * @notice This function transfers items across an array of tokens that can be ERC20, ERC721 and ERC1155. * @param items Array of BatchTransferItem * @param from Sender address * @param to Recipient address */ function transferBatchItemsAcrossCollections( BatchTransferItem[] calldata items, address from, address to ) external; /** * @notice This function allows a user to grant approvals for an array of operators. * Users cannot grant approvals if the operator is not allowed by this contract's owner. * @param operators Array of operator addresses * @dev Each operator address must be globally allowed to be approved. */ function grantApprovals(address[] calldata operators) external; /** * @notice This function allows a user to revoke existing approvals for an array of operators. * @param operators Array of operator addresses * @dev Each operator address must be approved at the user level to be revoked. */ function revokeApprovals(address[] calldata operators) external; /** * @notice This function allows an operator to be added for the shared transfer system. * Once the operator is allowed, users can grant NFT approvals to this operator. * @param operator Operator address to allow * @dev Only callable by owner. */ function allowOperator(address operator) external; /** * @notice This function allows the user to remove an operator for the shared transfer system. * @param operator Operator address to remove * @dev Only callable by owner. */ function removeOperator(address operator) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface VRFCoordinatorV2Interface { /** * @notice Get configuration relevant for making requests * @return minimumRequestConfirmations global min for request confirmations * @return maxGasLimit global max for request gas limit * @return s_provingKeyHashes list of registered key hashes */ function getRequestConfig() external view returns ( uint16, uint32, bytes32[] memory ); /** * @notice Request a set of random words. * @param keyHash - Corresponds to a particular oracle job which uses * that key for generating the VRF proof. Different keyHash's have different gas price * ceilings, so you can select a specific one to bound your maximum per request cost. * @param subId - The ID of the VRF subscription. Must be funded * with the minimum subscription balance required for the selected keyHash. * @param minimumRequestConfirmations - How many blocks you'd like the * oracle to wait before responding to the request. See SECURITY CONSIDERATIONS * for why you may want to request more. The acceptable range is * [minimumRequestBlockConfirmations, 200]. * @param callbackGasLimit - How much gas you'd like to receive in your * fulfillRandomWords callback. Note that gasleft() inside fulfillRandomWords * may be slightly less than this amount because of gas used calling the function * (argument decoding etc.), so you may need to request slightly more than you expect * to have inside fulfillRandomWords. The acceptable range is * [0, maxGasLimit] * @param numWords - The number of uint256 random values you'd like to receive * in your fulfillRandomWords callback. Note these numbers are expanded in a * secure way by the VRFCoordinator from a single random value supplied by the oracle. * @return requestId - A unique identifier of the request. Can be used to match * a request to a response in fulfillRandomWords. */ function requestRandomWords( bytes32 keyHash, uint64 subId, uint16 minimumRequestConfirmations, uint32 callbackGasLimit, uint32 numWords ) external returns (uint256 requestId); /** * @notice Create a VRF subscription. * @return subId - A unique subscription id. * @dev You can manage the consumer set dynamically with addConsumer/removeConsumer. * @dev Note to fund the subscription, use transferAndCall. For example * @dev LINKTOKEN.transferAndCall( * @dev address(COORDINATOR), * @dev amount, * @dev abi.encode(subId)); */ function createSubscription() external returns (uint64 subId); /** * @notice Get a VRF subscription. * @param subId - ID of the subscription * @return balance - LINK balance of the subscription in juels. * @return reqCount - number of requests for this subscription, determines fee tier. * @return owner - owner of the subscription. * @return consumers - list of consumer address which are able to use this subscription. */ function getSubscription(uint64 subId) external view returns ( uint96 balance, uint64 reqCount, address owner, address[] memory consumers ); /** * @notice Request subscription owner transfer. * @param subId - ID of the subscription * @param newOwner - proposed new owner of the subscription */ function requestSubscriptionOwnerTransfer(uint64 subId, address newOwner) external; /** * @notice Request subscription owner transfer. * @param subId - ID of the subscription * @dev will revert if original owner of subId has * not requested that msg.sender become the new owner. */ function acceptSubscriptionOwnerTransfer(uint64 subId) external; /** * @notice Add a consumer to a VRF subscription. * @param subId - ID of the subscription * @param consumer - New consumer which can use the subscription */ function addConsumer(uint64 subId, address consumer) external; /** * @notice Remove a consumer from a VRF subscription. * @param subId - ID of the subscription * @param consumer - Consumer to remove from the subscription */ function removeConsumer(uint64 subId, address consumer) external; /** * @notice Cancel a subscription * @param subId - ID of the subscription * @param to - Where to send the remaining LINK to */ function cancelSubscription(uint64 subId, address to) external; /* * @notice Check to see if there exists a request commitment consumers * for all consumers and keyhashes for a given sub. * @param subId - ID of the subscription * @return true if there exists at least one unfulfilled request for the subscription, false * otherwise. */ function pendingRequestExists(uint64 subId) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /** **************************************************************************** * @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. It ensures 2 things: * @dev 1. The fulfillment came from the VRFCoordinator * @dev 2. The consumer contract implements fulfillRandomWords. * ***************************************************************************** * @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) 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). Create subscription, fund it * @dev and your consumer contract as a consumer of it (see VRFCoordinatorInterface * @dev subscription management functions). * @dev Call requestRandomWords(keyHash, subId, minimumRequestConfirmations, * @dev callbackGasLimit, numWords), * @dev see (VRFCoordinatorInterface for a description of the arguments). * * @dev Once the VRFCoordinator has received and validated the oracle's response * @dev to your request, it will call your contract's fulfillRandomWords method. * * @dev The randomness argument to fulfillRandomWords is a set of random words * @dev generated from your requestId and the blockHash of the request. * * @dev If your contract could have concurrent requests open, you can use the * @dev requestId returned from requestRandomWords to track which response is associated * @dev with which randomness request. * @dev 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. * * ***************************************************************************** * @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 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. It is for this reason that * @dev that you can signal to an oracle you'd like them to wait longer before * @dev responding to the request (however this is not enforced in the contract * @dev and so remains effective only in the case of unmodified oracle software). */ abstract contract VRFConsumerBaseV2 { error OnlyCoordinatorCanFulfill(address have, address want); address private immutable vrfCoordinator; /** * @param _vrfCoordinator address of VRFCoordinator contract */ constructor(address _vrfCoordinator) { vrfCoordinator = _vrfCoordinator; } /** * @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 VRFConsumerBaseV2 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 randomWords the VRF output expanded to the requested number of words */ function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal virtual; // rawFulfillRandomness is called by VRFCoordinator when it receives a valid VRF // proof. rawFulfillRandomness then calls fulfillRandomness, after validating // the origin of the call function rawFulfillRandomWords(uint256 requestId, uint256[] memory randomWords) external { if (msg.sender != vrfCoordinator) { revert OnlyCoordinatorCanFulfill(msg.sender, vrfCoordinator); } fulfillRandomWords(requestId, randomWords); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.20; import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; /** * @dev Collection of functions related to array types. * Modified from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Arrays.sol */ library Arrays { /** * @dev 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. */ function findUpperBound(uint256[] memory array, uint256 element) internal pure 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] > element) { high = mid; } else { unchecked { 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] == element) { unchecked { return low - 1; } } else { return low; } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.20; /** * @title WinningEntrySearchLogicV2 * @notice This contract contains the logic to search for a winning entry. * @author LooksRare protocol team (👀,💎) */ contract WinningEntrySearchLogicV2 { /** * @param randomWord The random word. * @param currentEntryIndex The current entry index. * @param winningEntriesBitmap The bitmap of winning entries. */ function _searchForWinningEntryUntilThereIsNotADuplicate( uint256 randomWord, uint256 currentEntryIndex, uint256[] memory winningEntriesBitmap ) internal pure returns ( uint256, uint256, uint256[] memory ) { uint256 winningEntry = randomWord % (currentEntryIndex + 1); uint256 bucket = winningEntry >> 8; uint256 mask = 1 << (winningEntry & 0xff); while (winningEntriesBitmap[bucket] & mask != 0) { randomWord = uint256(keccak256(abi.encodePacked(randomWord))); winningEntry = randomWord % (currentEntryIndex + 1); bucket = winningEntry >> 8; mask = 1 << (winningEntry & 0xff); } winningEntriesBitmap[bucket] |= mask; return (randomWord, winningEntry, winningEntriesBitmap); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.20; interface IRaffleV2 { enum RaffleStatus { None, Open, Drawing, RandomnessFulfilled, Drawn, Complete, Refundable, Cancelled } enum TokenType { ERC721, ERC1155, ETH, ERC20 } /** * @param entriesCount The number of entries that can be purchased for the given price. * @param price The price of the entries. */ struct PricingOption { uint40 entriesCount; uint208 price; } /** * @param currentEntryIndex The cumulative number of entries in the raffle minus one. * @param participant The address of the participant. */ struct Entry { uint40 currentEntryIndex; address participant; } /** * @param participant The address of the winner. * @param claimed Whether the winner has claimed the prize. * @param prizeIndex The index of the prize that was won. * @param entryIndex The index of the entry that won. */ struct Winner { address participant; bool claimed; uint8 prizeIndex; uint40 entryIndex; } /** * @param winnersCount The number of winners. * @param cumulativeWinnersCount The cumulative number of winners in the raffle. * @param prizeType The type of the prize. * @param prizeTier The tier of the prize. * @param prizeAddress The address of the prize. * @param prizeId The id of the prize. * @param prizeAmount The amount of the prize. */ struct Prize { uint40 winnersCount; uint40 cumulativeWinnersCount; TokenType prizeType; uint8 prizeTier; address prizeAddress; uint256 prizeId; uint256 prizeAmount; } /** * @param owner The address of the raffle owner. * @param status The status of the raffle. * @param isMinimumEntriesFixed Whether the minimum number of entries is fixed. * @param cutoffTime The time after which the raffle cannot be entered. * @param drawnAt The time at which the raffle was drawn. It is still pending Chainlink to fulfill the randomness request. * @param minimumEntries The minimum number of entries required to draw the raffle. * @param maximumEntriesPerParticipant The maximum number of entries allowed per participant. * @param feeTokenAddress The address of the token to be used as a fee. If the fee token type is ETH, then this address is ignored. * @param protocolFeeBp The protocol fee in basis points. It must be equal to the protocol fee basis points when the raffle was created. * @param claimableFees The amount of fees collected from selling entries. * @param pricingOptions The pricing options for the raffle. * @param prizes The prizes to be distributed. * @param entries The entries that have been sold. * @param winners The winners of the raffle. */ struct Raffle { address owner; RaffleStatus status; bool isMinimumEntriesFixed; uint40 cutoffTime; uint40 drawnAt; uint40 minimumEntries; uint40 maximumEntriesPerParticipant; address feeTokenAddress; uint16 protocolFeeBp; uint208 claimableFees; PricingOption[] pricingOptions; Prize[] prizes; Entry[] entries; Winner[] winners; } /** * @param amountPaid The amount paid by the participant. * @param entriesCount The number of entries purchased by the participant. * @param refunded Whether the participant has been refunded. */ struct ParticipantStats { uint208 amountPaid; uint40 entriesCount; bool refunded; } /** * @param raffleId The id of the raffle. * @param pricingOptionIndex The index of the selected pricing option. * @param count The number of entries to be purchased. * @param recipient The recipient of the entries. */ struct EntryCalldata { uint256 raffleId; uint256 pricingOptionIndex; uint40 count; address recipient; } /** * @param cutoffTime The time at which the raffle will be closed. * @param minimumEntries The minimum number of entries required to draw the raffle. * @param isMinimumEntriesFixed Whether the minimum number of entries is fixed. * @param maximumEntriesPerParticipant The maximum number of entries allowed per participant. * @param protocolFeeBp The protocol fee in basis points. It must be equal to the protocol fee basis points when the raffle was created. * @param feeTokenAddress The address of the token to be used as a fee. If the fee token type is ETH, then this address is ignored. * @param prizes The prizes to be distributed. * @param pricingOptions The pricing options for the raffle. */ struct CreateRaffleCalldata { uint40 cutoffTime; bool isMinimumEntriesFixed; uint40 minimumEntries; uint40 maximumEntriesPerParticipant; uint16 protocolFeeBp; address feeTokenAddress; Prize[] prizes; PricingOption[] pricingOptions; } /** * @param raffleId The id of the raffle. * @param winnerIndices The indices of the winners to be claimed. */ struct ClaimPrizesCalldata { uint256 raffleId; uint256[] winnerIndices; } /** * @param exists Whether the request exists. * @param randomWord The random words returned by Chainlink VRF. * If randomWord == 0, then the request is still pending. * @param raffleId The id of the raffle. */ struct RandomnessRequest { bool exists; uint80 raffleId; uint256 randomWord; } /** * @notice This is used to accumulate the amount of tokens to be transferred. * @param tokenAddress The address of the token. * @param amount The amount of tokens accumulated. */ struct TransferAccumulator { address tokenAddress; uint256 amount; } event CurrenciesStatusUpdated(address[] currencies, bool isAllowed); event EntryRefunded(uint256 raffleId, address buyer, uint208 amount); event EntrySold(uint256 raffleId, address buyer, address recipient, uint40 entriesCount, uint208 price); event FeesClaimed(uint256 raffleId, uint256 amount); event PrizeClaimed(uint256 raffleId, uint256 winnerIndex); event PrizesClaimed(uint256 raffleId, uint256[] winnerIndex); event ProtocolFeeBpUpdated(uint16 protocolFeeBp); event ProtocolFeeRecipientUpdated(address protocolFeeRecipient); event RaffleStatusUpdated(uint256 raffleId, RaffleStatus status); event RandomnessRequested(uint256 raffleId, uint256 requestId); error CutoffTimeNotReached(); error CutoffTimeReached(); error DrawExpirationTimeNotReached(); error InsufficientNativeTokensSupplied(); error InvalidCaller(); error InvalidCount(); error InvalidCurrency(); error InvalidCutoffTime(); error InvalidIndex(); error InvalidPricingOption(); error InvalidPricingOptionsCount(); error InvalidPrize(); error InvalidPrizesCount(); error InvalidProtocolFeeBp(); error InvalidProtocolFeeRecipient(); error InvalidStatus(); error InvalidWinnersCount(); error MaximumEntriesPerParticipantReached(); error MaximumEntriesReached(); error NothingToClaim(); error NotEnoughEntries(); error RandomnessRequestAlreadyExists(); error RandomnessRequestDoesNotExist(); /** * @notice Creates a new raffle. * @param params The parameters of the raffle. * @return raffleId The id of the newly created raffle. */ function createRaffle(CreateRaffleCalldata calldata params) external payable returns (uint256 raffleId); /** * @notice Enters a raffle or multiple raffles. * @param entries The entries to be made. */ function enterRaffles(EntryCalldata[] calldata entries) external payable; /** * @notice Select the winners for a raffle based on the random words returned by Chainlink. * @param requestId The request id returned by Chainlink. */ function selectWinners(uint256 requestId) external; /** * @notice Claims a single prize for a winner. * @param raffleId The id of the raffle. * @param winnerIndex The index of the winner. */ function claimPrize(uint256 raffleId, uint256 winnerIndex) external; /** * @notice Claims the prizes for a winner. A winner can claim multiple prizes * from multiple raffles in a single transaction. * @param claimPrizesCalldata The calldata for claiming prizes. */ function claimPrizes(ClaimPrizesCalldata[] calldata claimPrizesCalldata) external; /** * @notice Claims the fees collected for a raffle. * @param raffleId The id of the raffle. */ function claimFees(uint256 raffleId) external; /** * @notice Cancels a raffle beyond cut-off time without meeting minimum entries. * @param raffleId The id of the raffle. */ function cancel(uint256 raffleId) external; /** * @notice Draws winners for a raffle beyond cut-off time without meeting minimum entries. * @param raffleId The id of the raffle. */ function drawWinners(uint256 raffleId) external; /** * @notice Cancels a raffle after randomness request if the randomness request * does not arrive after a certain amount of time. * Only callable by contract owner. * @param raffleId The id of the raffle. */ function cancelAfterRandomnessRequest(uint256 raffleId) external; /** * @notice Withdraws the prizes for a raffle after it has been marked as refundable. * @param raffleId The id of the raffle. */ function withdrawPrizes(uint256 raffleId) external; /** * @notice Rollover entries from cancelled raffles to open raffles. * @param refundableRaffleIds The ids of the refundable raffles. * @param entries The entries to be made. */ function rollover(uint256[] calldata refundableRaffleIds, EntryCalldata[] calldata entries) external payable; /** * @notice Claims the refund for a cancelled raffle. * @param raffleIds The ids of the raffles. */ function claimRefund(uint256[] calldata raffleIds) external; /** * @notice Sets the protocol fee in basis points. Only callable by contract owner. * @param protocolFeeBp The protocol fee in basis points. */ function setProtocolFeeBp(uint16 protocolFeeBp) external; /** * @notice Sets the protocol fee recipient. Only callable by contract owner. * @param protocolFeeRecipient The protocol fee recipient. */ function setProtocolFeeRecipient(address protocolFeeRecipient) external; /** * @notice This function allows the owner to update currency statuses. * @param currencies Currency addresses (address(0) for ETH) * @param isAllowed Whether the currencies should be allowed for trading * @dev Only callable by owner. */ function updateCurrenciesStatus(address[] calldata currencies, bool isAllowed) external; /** * @notice Toggle the contract's paused status. Only callable by contract owner. */ function togglePaused() external; /** * @notice Gets the winners for a raffle. * @param raffleId The id of the raffle. * @return winners The winners of the raffle. */ function getWinners(uint256 raffleId) external view returns (Winner[] memory); /** * @notice Gets the pricing options for a raffle. * @param raffleId The id of the raffle. * @return pricingOptions The pricing options for the raffle. */ function getPricingOptions(uint256 raffleId) external view returns (PricingOption[] memory); /** * @notice Gets the prizes for a raffle. * @param raffleId The id of the raffle. * @return prizes The prizes to be distributed. */ function getPrizes(uint256 raffleId) external view returns (Prize[] memory); /** * @notice Gets the entries for a raffle. * @param raffleId The id of the raffle. * @return entries The entries entered for the raffle. */ function getEntries(uint256 raffleId) external view returns (Entry[] memory); }
// SPDX-License-Identifier: MIT pragma solidity >=0.5.0; interface IWETH { function deposit() external payable; function transfer(address dst, uint256 wad) external returns (bool); function withdraw(uint256 wad) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; interface IERC20 { event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); function totalSupply() external view returns (uint256); function balanceOf(address account) external view returns (uint256); function transfer(address to, uint256 amount) external returns (bool); function allowance(address owner, address spender) external view returns (uint256); function approve(address spender, uint256 amount) external returns (bool); function transferFrom(address from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; /** * @notice It is emitted if the ETH transfer fails. */ error ETHTransferFail(); /** * @notice It is emitted if the ERC20 approval fails. */ error ERC20ApprovalFail(); /** * @notice It is emitted if the ERC20 transfer fails. */ error ERC20TransferFail(); /** * @notice It is emitted if the ERC20 transferFrom fails. */ error ERC20TransferFromFail(); /** * @notice It is emitted if the ERC721 transferFrom fails. */ error ERC721TransferFromFail(); /** * @notice It is emitted if the ERC1155 safeTransferFrom fails. */ error ERC1155SafeTransferFromFail(); /** * @notice It is emitted if the ERC1155 safeBatchTransferFrom fails. */ error ERC1155SafeBatchTransferFromFail();
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; /** * @notice It is emitted if the call recipient is not a contract. */ error NotAContract();
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; interface IERC721 { event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); event ApprovalForAll(address indexed owner, address indexed operator, bool approved); function balanceOf(address owner) external view returns (uint256 balance); function ownerOf(uint256 tokenId) external view returns (address owner); function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; function safeTransferFrom(address from, address to, uint256 tokenId) external; function transferFrom(address from, address to, uint256 tokenId) external; function approve(address to, uint256 tokenId) external; function setApprovalForAll(address operator, bool _approved) external; function getApproved(uint256 tokenId) external view returns (address operator); function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; interface IERC1155 { event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value); event TransferBatch( address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values ); event ApprovalForAll(address indexed account, address indexed operator, bool approved); event URI(string value, uint256 indexed id); function balanceOf(address account, uint256 id) external view returns (uint256); function balanceOfBatch( address[] calldata accounts, uint256[] calldata ids ) external view returns (uint256[] memory); function setApprovalForAll(address operator, bool approved) external; function isApprovedForAll(address account, address operator) external view returns (bool); function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external; function safeBatchTransferFrom( address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data ) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; /** * @title IOwnableTwoSteps * @author LooksRare protocol team (👀,💎) */ interface IOwnableTwoSteps { /** * @notice This enum keeps track of the ownership status. * @param NoOngoingTransfer The default status when the owner is set * @param TransferInProgress The status when a transfer to a new owner is initialized * @param RenouncementInProgress The status when a transfer to address(0) is initialized */ enum Status { NoOngoingTransfer, TransferInProgress, RenouncementInProgress } /** * @notice This is returned when there is no transfer of ownership in progress. */ error NoOngoingTransferInProgress(); /** * @notice This is returned when the caller is not the owner. */ error NotOwner(); /** * @notice This is returned when there is no renouncement in progress but * the owner tries to validate the ownership renouncement. */ error RenouncementNotInProgress(); /** * @notice This is returned when the transfer is already in progress but the owner tries * initiate a new ownership transfer. */ error TransferAlreadyInProgress(); /** * @notice This is returned when there is no ownership transfer in progress but the * ownership change tries to be approved. */ error TransferNotInProgress(); /** * @notice This is returned when the ownership transfer is attempted to be validated by the * a caller that is not the potential owner. */ error WrongPotentialOwner(); /** * @notice This is emitted if the ownership transfer is cancelled. */ event CancelOwnershipTransfer(); /** * @notice This is emitted if the ownership renouncement is initiated. */ event InitiateOwnershipRenouncement(); /** * @notice This is emitted if the ownership transfer is initiated. * @param previousOwner Previous/current owner * @param potentialOwner Potential/future owner */ event InitiateOwnershipTransfer(address previousOwner, address potentialOwner); /** * @notice This is emitted when there is a new owner. */ event NewOwner(address newOwner); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; /** * @title IReentrancyGuard * @author LooksRare protocol team (👀,💎) */ interface IReentrancyGuard { /** * @notice This is returned when there is a reentrant call. */ error ReentrancyFail(); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.20; enum TokenType { ERC20, ERC721, ERC1155 }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @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 / b + (a % b == 0 ? 0 : 1); } }
{ "remappings": [ "@chainlink/=node_modules/@chainlink/", "@ensdomains/=node_modules/@ensdomains/", "@eth-optimism/=node_modules/@eth-optimism/", "@looksrare/=node_modules/@looksrare/", "@openzeppelin/=node_modules/@openzeppelin/", "ds-test/=lib/forge-std/lib/ds-test/src/", "eth-gas-reporter/=node_modules/eth-gas-reporter/", "forge-std/=lib/forge-std/src/", "hardhat/=node_modules/hardhat/" ], "optimizer": { "enabled": true, "runs": 888888 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "viaIR": true, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_weth","type":"address"},{"internalType":"bytes32","name":"_keyHash","type":"bytes32"},{"internalType":"uint64","name":"_subscriptionId","type":"uint64"},{"internalType":"address","name":"_vrfCoordinator","type":"address"},{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_protocolFeeRecipient","type":"address"},{"internalType":"uint16","name":"_protocolFeeBp","type":"uint16"},{"internalType":"address","name":"_transferManager","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CutoffTimeNotReached","type":"error"},{"inputs":[],"name":"CutoffTimeReached","type":"error"},{"inputs":[],"name":"DrawExpirationTimeNotReached","type":"error"},{"inputs":[],"name":"ERC1155SafeTransferFromFail","type":"error"},{"inputs":[],"name":"ERC20TransferFail","type":"error"},{"inputs":[],"name":"ERC721TransferFromFail","type":"error"},{"inputs":[],"name":"InsufficientNativeTokensSupplied","type":"error"},{"inputs":[],"name":"InvalidCaller","type":"error"},{"inputs":[],"name":"InvalidCount","type":"error"},{"inputs":[],"name":"InvalidCurrency","type":"error"},{"inputs":[],"name":"InvalidCutoffTime","type":"error"},{"inputs":[],"name":"InvalidIndex","type":"error"},{"inputs":[],"name":"InvalidPricingOption","type":"error"},{"inputs":[],"name":"InvalidPricingOptionsCount","type":"error"},{"inputs":[],"name":"InvalidPrize","type":"error"},{"inputs":[],"name":"InvalidPrizesCount","type":"error"},{"inputs":[],"name":"InvalidProtocolFeeBp","type":"error"},{"inputs":[],"name":"InvalidProtocolFeeRecipient","type":"error"},{"inputs":[],"name":"InvalidStatus","type":"error"},{"inputs":[],"name":"InvalidWinnersCount","type":"error"},{"inputs":[],"name":"IsPaused","type":"error"},{"inputs":[],"name":"MaximumEntriesPerParticipantReached","type":"error"},{"inputs":[],"name":"MaximumEntriesReached","type":"error"},{"inputs":[],"name":"NoOngoingTransferInProgress","type":"error"},{"inputs":[],"name":"NotAContract","type":"error"},{"inputs":[],"name":"NotEnoughEntries","type":"error"},{"inputs":[],"name":"NotOwner","type":"error"},{"inputs":[],"name":"NotPaused","type":"error"},{"inputs":[],"name":"NothingToClaim","type":"error"},{"inputs":[{"internalType":"address","name":"have","type":"address"},{"internalType":"address","name":"want","type":"address"}],"name":"OnlyCoordinatorCanFulfill","type":"error"},{"inputs":[],"name":"RandomnessRequestAlreadyExists","type":"error"},{"inputs":[],"name":"RandomnessRequestDoesNotExist","type":"error"},{"inputs":[],"name":"ReentrancyFail","type":"error"},{"inputs":[],"name":"RenouncementNotInProgress","type":"error"},{"inputs":[],"name":"TransferAlreadyInProgress","type":"error"},{"inputs":[],"name":"TransferNotInProgress","type":"error"},{"inputs":[],"name":"WrongPotentialOwner","type":"error"},{"anonymous":false,"inputs":[],"name":"CancelOwnershipTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"currencies","type":"address[]"},{"indexed":false,"internalType":"bool","name":"isAllowed","type":"bool"}],"name":"CurrenciesStatusUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":false,"internalType":"address","name":"buyer","type":"address"},{"indexed":false,"internalType":"uint208","name":"amount","type":"uint208"}],"name":"EntryRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":false,"internalType":"address","name":"buyer","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint40","name":"entriesCount","type":"uint40"},{"indexed":false,"internalType":"uint208","name":"price","type":"uint208"}],"name":"EntrySold","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesClaimed","type":"event"},{"anonymous":false,"inputs":[],"name":"InitiateOwnershipRenouncement","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":false,"internalType":"address","name":"potentialOwner","type":"address"}],"name":"InitiateOwnershipTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"NewOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"winnerIndex","type":"uint256"}],"name":"PrizeClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"winnerIndex","type":"uint256[]"}],"name":"PrizesClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"protocolFeeBp","type":"uint16"}],"name":"ProtocolFeeBpUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"protocolFeeRecipient","type":"address"}],"name":"ProtocolFeeRecipientUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":false,"internalType":"enum IRaffleV2.RaffleStatus","name":"status","type":"uint8"}],"name":"RaffleStatusUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"requestId","type":"uint256"}],"name":"RandomnessRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"MAXIMUM_NUMBER_OF_PRIZES_PER_RAFFLE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAXIMUM_NUMBER_OF_WINNERS_PER_RAFFLE","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAXIMUM_PRICING_OPTIONS_PER_RAFFLE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAXIMUM_PROTOCOL_FEE_BP","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SUBSCRIPTION_ID","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"raffleId","type":"uint256"}],"name":"cancel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"raffleId","type":"uint256"}],"name":"cancelAfterRandomnessRequest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cancelOwnershipTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"raffleId","type":"uint256"}],"name":"claimFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"raffleId","type":"uint256"},{"internalType":"uint256","name":"winnerIndex","type":"uint256"}],"name":"claimPrize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"raffleId","type":"uint256"},{"internalType":"uint256[]","name":"winnerIndices","type":"uint256[]"}],"internalType":"struct IRaffleV2.ClaimPrizesCalldata[]","name":"claimPrizesCalldata","type":"tuple[]"}],"name":"claimPrizes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"raffleIds","type":"uint256[]"}],"name":"claimRefund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"confirmOwnershipRenouncement","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"confirmOwnershipTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint40","name":"cutoffTime","type":"uint40"},{"internalType":"bool","name":"isMinimumEntriesFixed","type":"bool"},{"internalType":"uint40","name":"minimumEntries","type":"uint40"},{"internalType":"uint40","name":"maximumEntriesPerParticipant","type":"uint40"},{"internalType":"uint16","name":"protocolFeeBp","type":"uint16"},{"internalType":"address","name":"feeTokenAddress","type":"address"},{"components":[{"internalType":"uint40","name":"winnersCount","type":"uint40"},{"internalType":"uint40","name":"cumulativeWinnersCount","type":"uint40"},{"internalType":"enum IRaffleV2.TokenType","name":"prizeType","type":"uint8"},{"internalType":"uint8","name":"prizeTier","type":"uint8"},{"internalType":"address","name":"prizeAddress","type":"address"},{"internalType":"uint256","name":"prizeId","type":"uint256"},{"internalType":"uint256","name":"prizeAmount","type":"uint256"}],"internalType":"struct IRaffleV2.Prize[]","name":"prizes","type":"tuple[]"},{"components":[{"internalType":"uint40","name":"entriesCount","type":"uint40"},{"internalType":"uint208","name":"price","type":"uint208"}],"internalType":"struct IRaffleV2.PricingOption[]","name":"pricingOptions","type":"tuple[]"}],"internalType":"struct IRaffleV2.CreateRaffleCalldata","name":"params","type":"tuple"}],"name":"createRaffle","outputs":[{"internalType":"uint256","name":"raffleId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"raffleId","type":"uint256"}],"name":"drawWinners","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"raffleId","type":"uint256"},{"internalType":"uint256","name":"pricingOptionIndex","type":"uint256"},{"internalType":"uint40","name":"count","type":"uint40"},{"internalType":"address","name":"recipient","type":"address"}],"internalType":"struct IRaffleV2.EntryCalldata[]","name":"entries","type":"tuple[]"}],"name":"enterRaffles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"raffleId","type":"uint256"}],"name":"getEntries","outputs":[{"components":[{"internalType":"uint40","name":"currentEntryIndex","type":"uint40"},{"internalType":"address","name":"participant","type":"address"}],"internalType":"struct IRaffleV2.Entry[]","name":"entries","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"raffleId","type":"uint256"}],"name":"getPricingOptions","outputs":[{"components":[{"internalType":"uint40","name":"entriesCount","type":"uint40"},{"internalType":"uint208","name":"price","type":"uint208"}],"internalType":"struct IRaffleV2.PricingOption[]","name":"pricingOptions","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"raffleId","type":"uint256"}],"name":"getPrizes","outputs":[{"components":[{"internalType":"uint40","name":"winnersCount","type":"uint40"},{"internalType":"uint40","name":"cumulativeWinnersCount","type":"uint40"},{"internalType":"enum IRaffleV2.TokenType","name":"prizeType","type":"uint8"},{"internalType":"uint8","name":"prizeTier","type":"uint8"},{"internalType":"address","name":"prizeAddress","type":"address"},{"internalType":"uint256","name":"prizeId","type":"uint256"},{"internalType":"uint256","name":"prizeAmount","type":"uint256"}],"internalType":"struct IRaffleV2.Prize[]","name":"prizes","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"raffleId","type":"uint256"}],"name":"getWinners","outputs":[{"components":[{"internalType":"address","name":"participant","type":"address"},{"internalType":"bool","name":"claimed","type":"bool"},{"internalType":"uint8","name":"prizeIndex","type":"uint8"},{"internalType":"uint40","name":"entryIndex","type":"uint40"}],"internalType":"struct IRaffleV2.Winner[]","name":"winners","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initiateOwnershipRenouncement","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newPotentialOwner","type":"address"}],"name":"initiateOwnershipTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isCurrencyAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ownershipStatus","outputs":[{"internalType":"enum IOwnableTwoSteps.Status","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"potentialOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeBp","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"raffles","outputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"enum IRaffleV2.RaffleStatus","name":"status","type":"uint8"},{"internalType":"bool","name":"isMinimumEntriesFixed","type":"bool"},{"internalType":"uint40","name":"cutoffTime","type":"uint40"},{"internalType":"uint40","name":"drawnAt","type":"uint40"},{"internalType":"uint40","name":"minimumEntries","type":"uint40"},{"internalType":"uint40","name":"maximumEntriesPerParticipant","type":"uint40"},{"internalType":"address","name":"feeTokenAddress","type":"address"},{"internalType":"uint16","name":"protocolFeeBp","type":"uint16"},{"internalType":"uint208","name":"claimableFees","type":"uint208"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rafflesCount","outputs":[{"internalType":"uint80","name":"","type":"uint80"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"rafflesParticipantsStats","outputs":[{"internalType":"uint208","name":"amountPaid","type":"uint208"},{"internalType":"uint40","name":"entriesCount","type":"uint40"},{"internalType":"bool","name":"refunded","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"randomnessRequests","outputs":[{"internalType":"bool","name":"exists","type":"bool"},{"internalType":"uint80","name":"raffleId","type":"uint80"},{"internalType":"uint256","name":"randomWord","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"requestId","type":"uint256"},{"internalType":"uint256[]","name":"randomWords","type":"uint256[]"}],"name":"rawFulfillRandomWords","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"refundableRaffleIds","type":"uint256[]"},{"components":[{"internalType":"uint256","name":"raffleId","type":"uint256"},{"internalType":"uint256","name":"pricingOptionIndex","type":"uint256"},{"internalType":"uint40","name":"count","type":"uint40"},{"internalType":"address","name":"recipient","type":"address"}],"internalType":"struct IRaffleV2.EntryCalldata[]","name":"entries","type":"tuple[]"}],"name":"rollover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"requestId","type":"uint256"}],"name":"selectWinners","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_protocolFeeBp","type":"uint16"}],"name":"setProtocolFeeBp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_protocolFeeRecipient","type":"address"}],"name":"setProtocolFeeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"togglePaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"currencies","type":"address[]"},{"internalType":"bool","name":"isAllowed","type":"bool"}],"name":"updateCurrenciesStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"raffleId","type":"uint256"}],"name":"withdrawPrizes","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
61014034620002695762005cfc601f38829003908101601f19168301906001600160401b0390818311858410176200026e5780859460409485528539610100948591810103126200026957620000558362000284565b9060208401518385015191821682036200026957620000776060860162000284565b90620000866080870162000284565b936200009560a0880162000284565b60c088015161ffff811698898203620002695760e0620000b6910162000284565b6080869052600080546001600160a01b0319166001600160a01b03998a1690811790915589519081529099907f3edd90e7770f06fafde38004653b33870066c33bfc923ff6102acd601f85dfbc90602090a16001805460ff60a81b1916600160a81b1790556109c4811162000258577fede4aee4284b8033b84c1aadcc51b229a4e46e6b42ab40092e237f07508b46266020600654928b51908152a187831692831562000247576001600160501b0390911660f09290921b6001600160f01b0319169190911760509190911b600160501b600160f01b031617600655865190815285939291907fc1b5345cce283376356748dc57f2dfa7120431d016fc7ca9ba641bc65f91411d90602090a160a05260c05216855260e052610120921682525190615a6292836200029a843960805183615545015260a0518381816141750152614fe7015260c05183614349015260e051838181610316015261436f015251826143be015251818181610bb801528181610c5701528181610d1c01528181610e1b01528181610ec00152614c420152f35b8951633106a0c760e01b8152600490fd5b8851634929acd760e01b8152600490fd5b600080fd5b634e487b7160e01b600052604160045260246000fd5b51906001600160a01b0382168203620002695756fe6080604052600436101561001257600080fd5b60003560e01c8063030932bb146102c25780630d64d5a6146102bd5780631e9f1a82146102b85780631fe543e3146102b3578063208b3d34146102ae57806323452b9c146102a95780632a6a4eb8146102a45780632bb5a9e61461029f57806331fe74a91461029a57806336566f061461029557806339a2eb2a146102905780633b6cb153146102545780633e5675391461028b57806340e58ee51461028657806349890e15146102815780634d2c53cd1461027c578063534fff0e146102775780635a195d19146102725780635b6ac0111461026d5780635c975abb146102685780635cb6dfff146102635780635d4bc0ce1461025e57806364df049e1461025957806365d697f7146102545780636b1426a41461024f5780636b7e4e3f1461024a5780636f30d7b5146102455780637200b829146102405780637762df251461023b5780637b154140146102365780638da5cb5b1461023157806398753c461461022c578063a17be15414610227578063a72844ba14610222578063ac68a7481461021d578063c0b6f56114610218578063cc30779514610213578063d1d06b2e1461020e578063d3549ebd14610209578063e521cb9214610204578063ea9bf39d146101ff578063f23a6e61146101fa5763f54a6f83146101f557600080fd5b613546565b6134a1565b613467565b613360565b6132aa565b613149565b613032565b612e7d565b612be3565b612aec565b612a37565b6129f8565b6129a6565b61277f565b61272d565b6125be565b61223d565b612073565b611f94565b611734565b611ebe565b611df3565b611cdb565b611c97565b611bbb565b611b52565b6119e2565b61199a565b61195f565b61186c565b61176e565b61148a565b611344565b6112a8565b6111f0565b6110e9565b610fcd565b6107aa565b610700565b6104f0565b61036b565b6102d7565b60009103126102d257565b600080fd5b346102d25760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257602060405167ffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b9181601f840112156102d25782359167ffffffffffffffff83116102d2576020808501948460071b0101116102d257565b60207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d25760043567ffffffffffffffff81116102d2576103b590369060040161033a565b600260ff60015460a81c161461048b5761043a79ffffffffffffffffffffffffffffffffffffffffffffffffffff916104449361042d75020000000000000000000000000000000000000000007fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff6001541617600155565b6104356156b2565b61466f565b9190911690614c19565b61048975010000000000000000000000000000000000000000007fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff6001541617600155565b005b60046040517f1bbee726000000000000000000000000000000000000000000000000000000008152fd5b9181601f840112156102d25782359167ffffffffffffffff83116102d2576020808501948460051b0101116102d257565b801515036102d257565b346102d2576040807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257600490813567ffffffffffffffff81116102d25761054190369084016104b5565b916024359361054f856104e6565b610557615667565b60005b8481106105985750507fcb2fef16ee9f3ea43e174daf88ffcdc8beee4ad884c7570093d998d71058698793610593915193849384613b8e565b0390a1005b600190600087156105e6575060ff825b73ffffffffffffffffffffffffffffffffffffffff6105c8848a8a613aa0565b356105d281611b27565b16600052846020521684600020550161055a565b60ff906105a8565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b67ffffffffffffffff811161063157604052565b6105ee565b6080810190811067ffffffffffffffff82111761063157604052565b60e0810190811067ffffffffffffffff82111761063157604052565b6040810190811067ffffffffffffffff82111761063157604052565b610100810190811067ffffffffffffffff82111761063157604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761063157604052565b67ffffffffffffffff81116106315760051b60200190565b346102d25760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d25760243567ffffffffffffffff81116102d257366023820112156102d25780600401359061075b826106e8565b9061076960405192836106a7565b82825260209260248484019160051b830101913683116102d257602401905b82821061079b5761048984600435615542565b81358152908401908401610788565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6020813601126102d25767ffffffffffffffff600435116102d25761010090600435360301126102d257600260ff60015460a81c161461048b5761084a75020000000000000000000000000000000000000000007fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff6001541617600155565b6108526156b2565b6108606004356004016135e7565b64ffffffffff81168062015180420111908115610fbe575b50610f945761088b6084600435016135f4565b600654908160f01c61ffff821603610f6a576108ab60a4600435016135fe565b9073ffffffffffffffffffffffffffffffffffffffff8216610f5c575b6108dc60c460043501600435600401613608565b80939150158015610f52575b610f285769ffffffffffffffffffff9461093a866001818816011669ffffffffffffffffffff167fffffffffffffffffffffffffffffffffffffffffffff000000000000000000006006541617600655565b85600181871601166000526002602052604060002093600485016000526020600020906000906000926000906000915b838310610b0057505050600487015561098290614fa0565b64ffffffffff6109966044600435016135e7565b911664ffffffffff82168111908115610af5575b50610acb576001936109d76109c960e4600435016004356004016137f2565b90848b89818d160116613ce8565b740100000000000000000000000000000000000000006109fb602460043501613846565b610a096064600435016135e7565b9460b01b9060a81b33171717865560f01b9260501b9160281b1717179101557fc1191e7178b58ad510709587719f39ec315fa79e81ee7ba5c5ef3c894e94a65160405180610a6c8560018187160116826020600191939293604081019481520152565b0390a1610ab475010000000000000000000000000000000000000000007fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff6001541617600155565b6040519082166001019091168152602090f35b0390f35b60046040517f804a1e02000000000000000000000000000000000000000000000000000000008152fd5b60c8915011386109aa565b610b29610b2484610b1e60c460049a979a3501600435600401613608565b9061368b565b6136ae565b9560ff610b3a606089015160ff1690565b921660ff831610610efe57610b4e87613fb0565b604087015196610b5d88612f7e565b805164ffffffffff1694610b88608083015173ffffffffffffffffffffffffffffffffffffffff1690565b60c060a084015193015192610b9c8b612f7e565b8a610ce25773ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163b156102d2576040517fcda20f0b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83166004820152336024820152306044820152606481018290529560008780608481015b03818373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165af1968715610cdd5789600295610c979260019a610cc4575b505b6137d9565b9b8c829a600389028b019560601b9360581b9260501b9160281b171717178255858201550155019161096a565b80610cd1610cd79261061d565b806102c7565b38610c90565b613785565b610ceb8b612f7e565b60038b03610da557610d0464ffffffffff891685613772565b9573ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163b156102d2576040517fda3e8ce400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8416600482015233602482015230604482015260648101979097526000878060848101610c3d565b9198610db58b9692949596612f7e565b60028b03610deb5791600195949391610c9789610de5600296610ddf64ffffffffff84168a613772565b9061379f565b9c6137d9565b9891610e0364ffffffffff8997969593971685613772565b9573ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163b156102d2576040517fe62edc3500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841660048201523360248201523060448201526064810183905260848101979097526000878060a4810103818373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165af1968715610cdd5789600295610c979260019a610cc457506137d9565b60046040517f5f12e2ee000000000000000000000000000000000000000000000000000000008152fd5b60046040517fab13062d000000000000000000000000000000000000000000000000000000008152fd5b5060c883116108e8565b610f6582614f73565b6108c8565b60046040517f4929acd7000000000000000000000000000000000000000000000000000000008152fd5b60046040517fce8f4bfd000000000000000000000000000000000000000000000000000000008152fd5b905062093a8042011038610878565b346102d2576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126110da57611005615667565b60015460ff8160a01c1660038110156110d55780156110ab578061102a6001926111e6565b14611080575b507fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff600154166001557f8eca980489e87f7dba4f26917aa4bfc906eb3f2b4f7b4b9fd0ff2b8bb3e21ae38180a180f35b7fffffffffffffffffffffffff00000000000000000000000000000000000000001660015538611030565b60046040517fccf69db7000000000000000000000000000000000000000000000000000000008152fd5b6111b7565b80fd5b61ffff8116036102d257565b346102d25760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257600435611124816110dd565b61112c615667565b61ffff8116906109c48211610f6a577fede4aee4284b8033b84c1aadcc51b229a4e46e6b42ab40092e237f07508b4626916020917dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffff0000000000000000000000000000000000000000000000000000000000006006549260f01b16911617600655604051908152a1005b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600311156110d557565b346102d25760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d25760ff60015460a01c1660405160038210156110d5576020918152f35b60208082019080835283518092528060408094019401926000905b83821061126557505050505090565b8451805164ffffffffff16875283015179ffffffffffffffffffffffffffffffffffffffffffffffffffff16868401529485019493820193600190910190611256565b346102d2576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d25760043560005260028152600360406000200180546112f5816106e8565b9161130360405193846106a7565b8183526000908152838120938084015b8383106113285760405180610ac7878261123b565b600182819261133689613bfc565b815201960192019194611313565b346102d25760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d25761137b615667565b60015460ff8160b01c16600014611417575060015460ff8160b01c16156113ed577fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff166001557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6020604051338152a1005b60046040517f6cd60201000000000000000000000000000000000000000000000000000000008152fd5b7fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff760100000000000000000000000000000000000000000000916114596156b2565b16176001557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a1005b346102d2576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d2576114d86114d36004356000526005602052604060002090565b613850565b6114e96114e58251151590565b1590565b61170a576115156115068383015169ffffffffffffffffffff1690565b69ffffffffffffffffffff1690565b9161152a836000526002602052604060002090565b9261153484614555565b61153e8185615052565b6004840191825493611583600561157c61157261156361155d8a613899565b896138c6565b505460281c64ffffffffff1690565b64ffffffffff1690565b97016138e2565b80519361158f8561396b565b9460005b8181106116da57506115a76115ad91613899565b866139c7565b51916115c36115be8460081c613791565b61396b565b976115cd8161396b565b9760005b8281106116b657505050604080940151916000526002855260068460002001978860005285600020936000935b8b851061160a578b8b55005b89946116346116508a6116228d978761162e976153e1565b908095929791996154a0565b896139c7565b51015173ffffffffffffffffffffffffffffffffffffffff1690565b61165e6001840180996154a0565b60a81b179060b01b179087015586516116ae816116828b8201948560209181520190565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018352826106a7565b5190206115fe565b806116c9611572611563600194866138c6565b6116d3828d6139c7565b52016115d1565b806116f96115726116ed600194886139c7565b515164ffffffffff1690565b611703828a6139c7565b5201611593565b60046040517f1b71a84c000000000000000000000000000000000000000000000000000000008152fd5b346102d25760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257602060405160c88152f35b346102d2576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126110da576117a6615667565b60ff60015460a01c1660038110156110d557600203611842577fffffffffffffffffffffffff000000000000000000000000000000000000000081541681556118127fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff60015416600155565b604051600081527f3edd90e7770f06fafde38004653b33870066c33bfc923ff6102acd601f85dfbc90602090a180f35b60046040517f045c5122000000000000000000000000000000000000000000000000000000008152fd5b346102d25760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257600435600260ff60015460a81c161461048b57610444906118f775020000000000000000000000000000000000000000007fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff6001541617600155565b6118ff6156b2565b80600052600260205260406000206119168161500b565b805464ffffffffff61192c818360b01c166137ac565b16421061193a575b506150c2565b73ffffffffffffffffffffffffffffffffffffffff6119599116614f2b565b38611934565b346102d25760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d25760206040516109c48152f35b346102d25760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257602069ffffffffffffffffffff60065416604051908152f35b346102d25760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257600435600190600260ff835460a81c161461048b57611a6b75020000000000000000000000000000000000000000007fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff6001541617600155565b611a736156b2565b806000526002602052611a94604060002091611a8e83614598565b82615132565b6004810173ffffffffffffffffffffffffffffffffffffffff815492541660005b838110611b015761048975010000000000000000000000000000000000000000007fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff6001541617600155565b80611b21611b108793866138c6565b508464ffffffffff825416916140de565b01611ab5565b73ffffffffffffffffffffffffffffffffffffffff8116036102d257565b3590611b5082611b27565b565b346102d25760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d25773ffffffffffffffffffffffffffffffffffffffff600435611ba281611b27565b1660005260046020526020604060002054604051908152f35b346102d2576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126110da57611bf3615667565b60015460ff8160a01c1660038110156110d557611c6d577fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674020000000000000000000000000000000000000000176001557f3ff05a45e46337fa1cbf20996d2eeb927280bce099f37252bcca1040609604ec8180a180f35b60046040517f74ed79ae000000000000000000000000000000000000000000000000000000008152fd5b346102d25760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257602060ff60015460b01c166040519015158152f35b346102d25760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d2576004356000526005602052606060406000206001815491015469ffffffffffffffffffff6040519260ff81161515845260081c1660208301526040820152f35b600811156110d557565b9893969a999597919a9290926101408a019b73ffffffffffffffffffffffffffffffffffffffff8095168b5260088110156110d5576101209979ffffffffffffffffffffffffffffffffffffffffffffffffffff9961ffff988d9560609460208801521515604087015264ffffffffff958694858094169101521660808d01521660a08b01521660c08901521660e08701521661010085015216910152565b346102d25760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257600435600052600260205260406000208054610ac7611e636002600185015494015479ffffffffffffffffffffffffffffffffffffffffffffffffffff1690565b60405193849373ffffffffffffffffffffffffffffffffffffffff9164ffffffffff928160f01c93818360501c169381808560281c169416928160d81c928260b01c169160ff8160a81c169160ff8260a01c1691168b611d54565b346102d25760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257602073ffffffffffffffffffffffffffffffffffffffff60065460501c16604051908152f35b60208082019080835283518092528060408094019401926000905b838210611f3d57505050505090565b8451805173ffffffffffffffffffffffffffffffffffffffff168752808401511515878501528082015160ff168783015260609081015164ffffffffff169087015260809095019493820193600190910190611f2e565b346102d2576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d2576004356000526002815260409060068260002001805490611fe4826106e8565b92611ff1855194856106a7565b82845260009182528082208185015b84841061201457865180610ac78882611f13565b6001838192895161202481610636565b64ffffffffff865473ffffffffffffffffffffffffffffffffffffffff8116835260ff808260a01c161515868501528160a81c168d84015260b01c166060820152815201920193019290612000565b60407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d25767ffffffffffffffff6004358181116102d2576120be9036906004016104b5565b916024359081116102d2576120d790369060040161033a565b929091600260ff60015460a81c161461048b5761214c916121449161213775020000000000000000000000000000000000000000007fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff6001541617600155565b61213f6156b2565b614ce4565b93909261466f565b9073ffffffffffffffffffffffffffffffffffffffff809116908316036121c65779ffffffffffffffffffffffffffffffffffffffffffffffffffff9081169216828111156121a35791610444920390339061414d565b8281106121b3575b505050610444565b6121be920390614c19565b3880806121ab565b60046040517ff5993428000000000000000000000000000000000000000000000000000000008152fd5b60207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8201126102d2576004359067ffffffffffffffff82116102d257612239916004016104b5565b9091565b346102d25761224b366121f0565b90600260ff60015460a81c161461048b576122a175020000000000000000000000000000000000000000007fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff6001541617600155565b6122a96156b2565b6122b16139f3565b9160005b81811061231a5783602081015161230b5761048975010000000000000000000000000000000000000000007fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff6001541617600155565b61231490614290565b80610444565b612325818385613a0c565b61233a81356000526002602052604060002090565b90600461234c835460ff9060a01c1690565b61235581611d4a565b036125b0575b6123686020820182613a4c565b9092600681015460005b8381106123bc57505050917f0d0ab4a45afc0276ae825be9eeb4552011b19aad5c92b4bb782f3ca0356fedc5916123b3600195946040519384933584613ab0565b0390a1016122b5565b6123c7818588613aa0565b3582811015612586576123dd90600685016139db565b509081549160ff8360a01c1661255c5760019261246861245f8e9361241873ffffffffffffffffffffffffffffffffffffffff809516614f2b565b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001781555460a81c60ff1690565b600488016138c6565b50908461247a835460ff9060501c1690565b61248381612f7e565b111561254a57815460601c906124c96124b0855173ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1690565b908216036124f057506002915001546124e760208d0191825161379f565b90525b01612372565b9061251d60029260208501948551612526579073ffffffffffffffffffffffffffffffffffffffff169052565b015490526124ea565b61252f81614290565b9073ffffffffffffffffffffffffffffffffffffffff169052565b506125579150339061405e565b6124ea565b60046040517f969bf728000000000000000000000000000000000000000000000000000000008152fd5b60046040517f63df8171000000000000000000000000000000000000000000000000000000008152fd5b6125b9826145b1565b61235b565b346102d25760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257600154600160ff8260a01c16612602816111e6565b036127035773ffffffffffffffffffffffffffffffffffffffff1633036126d957600080547fffffffffffffffffffffffff0000000000000000000000000000000000000000163317905561267a7fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff60015416600155565b6126a77fffffffffffffffffffffffff000000000000000000000000000000000000000060015416600155565b6040513381527f3edd90e7770f06fafde38004653b33870066c33bfc923ff6102acd601f85dfbc908060208101610593565b60046040517fafdcfb92000000000000000000000000000000000000000000000000000000008152fd5b60046040517f5e4f2826000000000000000000000000000000000000000000000000000000008152fd5b346102d25760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257602073ffffffffffffffffffffffffffffffffffffffff60015416604051908152f35b346102d25760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d2576004803560243590600260ff60015460a81c161461297d5761280b75020000000000000000000000000000000000000000007fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff6001541617600155565b6128136156b2565b612827816000526002602052604060002090565b8054849060a01c60ff1661283a81611d4a565b0361296f575b6006810180548410156129465783612857916139db565b50805460ff8160a01c1661291d57917fd53b67ba94a5d6268d11caa5d2693557779404ed02fc9825d86d2894d29cb8fd956128b16128b89361241873ffffffffffffffffffffffffffffffffffffffff6128c09716614f2b565b91016138c6565b50339061405e565b60408051918252602082019290925290819081015b0390a161048975010000000000000000000000000000000000000000007fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff6001541617600155565b856040517f969bf728000000000000000000000000000000000000000000000000000000008152fd5b846040517f63df8171000000000000000000000000000000000000000000000000000000008152fd5b612978816145b1565b612840565b826040517f1bbee726000000000000000000000000000000000000000000000000000000008152fd5b346102d25760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257602073ffffffffffffffffffffffffffffffffffffffff60005416604051908152f35b346102d25760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257602060065460f01c604051908152f35b346102d25760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d2576060612aac602435612a7781611b27565b600435600052600360205260406000209073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b546040519079ffffffffffffffffffffffffffffffffffffffffffffffffffff8116825264ffffffffff8160d01c16602083015260f81c15156040820152f35b346102d25760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257600435600260ff60015460a81c161461048b57612b7375020000000000000000000000000000000000000000007fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff6001541617600155565b612b7b6156b2565b806000526002602052604060002090612b93826145ca565b815460d81c620151808101809111612bde574210612bb457610444916150c2565b60046040517ff4c0ca6e000000000000000000000000000000000000000000000000000000008152fd5b613732565b346102d25760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257600435600260ff60015460a81c161461048b577fa1f87f32d0f17fab0242ca800d736293de8988c14b27747e218cf13d5c249f5390612c8c75020000000000000000000000000000000000000000007fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff6001541617600155565b612c946156b2565b80612ca9816000526002602052604060002090565b612cb2816145e3565b612d9a612cd3825473ffffffffffffffffffffffffffffffffffffffff1690565b9173ffffffffffffffffffffffffffffffffffffffff83163303612e51575b612de66002820191612ddf612d21845479ffffffffffffffffffffffffffffffffffffffffffffffffffff1690565b93612dc26001840191612d6f612d4b612d45612d3e865460f01c90565b61ffff1690565b89613af8565b79ffffffffffffffffffffffffffffffffffffffffffffffffffff61271091160490565b97889779ffffffffffffffffffffffffffffffffffffffffffffffffffff998a9103169b8c966151a2565b7fffffffffffff00000000000000000000000000000000000000000000000000008154169055565b5460501c73ffffffffffffffffffffffffffffffffffffffff1690565b948561414d565b1680612e23575b50506040805191825279ffffffffffffffffffffffffffffffffffffffffffffffffffff909216602082015290819081016128d5565b600654612e4a929060501c73ffffffffffffffffffffffffffffffffffffffff169061414d565b3880612ded565b612e78612e7360005473ffffffffffffffffffffffffffffffffffffffff1690565b614f2b565b612cf2565b346102d25760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257600435612eb881611b27565b612ec0615667565b60015460ff8160a01c1660038110156110d557611c6d577fffffffffffffffffffffff0000000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff82161774010000000000000000000000000000000000000000176001557fb86c75c9bffca616b2d314cc914f7c3f1d174255b16b941c3f3ededee276d5ef90610593906040805133815273ffffffffffffffffffffffffffffffffffffffff909216602083015290918291820190565b600411156110d557565b60208082019080835283518092528060408094019401926000905b838210612fb257505050505090565b9091929394855164ffffffffff8082511683528582015116858301528281015160048110156110d5578284015260608181015160ff169083015260808082015173ffffffffffffffffffffffffffffffffffffffff169083015260a0808201519083015260c0908101519082015260e00194830193929160010190612fa3565b346102d2576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257600435600052600280825260409160048360002001805491613083836106e8565b93613090865195866106a7565b8385526000928352818320908286015b8585106130b457875180610ac78982612f88565b6003846001928a516130c581610652565b613129875464ffffffffff80821684528160281c16858401528d6130f360ff91828460501c16908601613bf0565b6131096060918360581c168286019060ff169052565b1c608083019073ffffffffffffffffffffffffffffffffffffffff169052565b8487015460a08201528587015460c08201528152019301940193916130a0565b346102d25760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257600435600260ff60015460a81c161461048b576131d075020000000000000000000000000000000000000000007fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff6001541617600155565b6131d86156b2565b6131ec816000526002602052604060002090565b6005810180549081156132805761324661157261324161323564ffffffffff9461322f61322961156360048b016132238154613899565b906138c6565b97613899565b906139db565b505464ffffffffff1690565b6137c3565b911611613280576104449161325a8261500b565b61327b612e73835473ffffffffffffffffffffffffffffffffffffffff1690565b6142c8565b60046040517f9358a89d000000000000000000000000000000000000000000000000000000008152fd5b346102d2576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257600435600052600281526040906132f6600583600020016138e2565b8251928284938401908085528351809252808386019401926000905b83821061331f5786860387f35b8451805164ffffffffff16875283015173ffffffffffffffffffffffffffffffffffffffff1686840152879650948501949382019360019190910190613312565b346102d25760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d25760043561339b81611b27565b6133a3615667565b73ffffffffffffffffffffffffffffffffffffffff811690811561343d577fc1b5345cce283376356748dc57f2dfa7120431d016fc7ca9ba641bc65f91411d916020917fffff0000000000000000000000000000000000000000ffffffffffffffffffff7dffffffffffffffffffffffffffffffffffffffff000000000000000000006006549260501b16911617600655604051908152a1005b60046040517f3106a0c7000000000000000000000000000000000000000000000000000000008152fd5b346102d25760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257602060405160058152f35b346102d25760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d2576134db600435611b27565b6134e6602435611b27565b60843567ffffffffffffffff8082116102d257366023830112156102d25781600401359081116102d257369101602401116102d2576040517ff23a6e61000000000000000000000000000000000000000000000000000000008152602090f35b346102d257613554366121f0565b600260ff60015460a81c161461048b576135cc79ffffffffffffffffffffffffffffffffffffffffffffffffffff916104449361213775020000000000000000000000000000000000000000007fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff6001541617600155565b9190911690339061414d565b64ffffffffff8116036102d257565b356135f1816135d8565b90565b356135f1816110dd565b356135f181611b27565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156102d2570180359067ffffffffffffffff82116102d2576020019160e08202360383136102d257565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b919081101561369b5760e0020190565b61365c565b359060ff821682036102d257565b60e0813603126102d257604051906136c582610652565b80356136d0816135d8565b825260208101356136e0816135d8565b602083015260408101359060048210156102d25760c0916040840152613708606082016136a0565b606084015261371960808201611b45565b608084015260a081013560a0840152013560c082015290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9081156001838004141715612bde57565b81810292918115918404141715612bde57565b6040513d6000823e3d90fd5b9060018201809211612bde57565b91908201809211612bde57565b90610e1064ffffffffff80931601918211612bde57565b90600164ffffffffff80931601918211612bde57565b91909164ffffffffff80809416911601918211612bde57565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156102d2570180359067ffffffffffffffff82116102d257602001918160061b360383136102d257565b356135f1816104e6565b906040516060810181811067ffffffffffffffff8211176106315760405260406001829469ffffffffffffffffffff815460ff81161515865260081c1660208501520154910152565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8201918211612bde57565b805482101561369b576000526003602060002091020190600090565b9081546138ee816106e8565b926040936138fe855191826106a7565b828152809460208092019260005281600020906000935b85851061392457505050505050565b600184819284516139348161066e565b73ffffffffffffffffffffffffffffffffffffffff875464ffffffffff8116835260281c1683820152815201930194019391613915565b90613975826106e8565b61398260405191826106a7565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06139b082946106e8565b0190602036910137565b80511561369b5760200190565b805182101561369b5760209160051b010190565b805482101561369b5760005260206000200190600090565b60405190613a008261066e565b60006020838281520152565b919081101561369b5760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc1813603018212156102d2570190565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156102d2570180359067ffffffffffffffff82116102d257602001918160051b360383136102d257565b919081101561369b5760051b0190565b908152604060208201528260408201527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83116102d25760609260051b809284830137010190565b919079ffffffffffffffffffffffffffffffffffffffffffffffffffff8080941691169283820216928184041490151715612bde57565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b9079ffffffffffffffffffffffffffffffffffffffffffffffffffff809116918215613b8957160490565b613b2f565b6040808252810183905292939291606083019060005b818110613bb957505060209150931515910152565b909160019073ffffffffffffffffffffffffffffffffffffffff8535613bde81611b27565b16815260209485019401929101613ba4565b60048210156110d55752565b90604051613c098161066e565b915464ffffffffff8116835260281c79ffffffffffffffffffffffffffffffffffffffffffffffffffff166020830152565b901561369b5790565b919081101561369b5760061b0190565b6040813603126102d257602060405191613c6d8361066e565b8035613c78816135d8565b8352013579ffffffffffffffffffffffffffffffffffffffffffffffffffff811681036102d257602082015290565b9064ffffffffff809116918215613b8957160690565b9079ffffffffffffffffffffffffffffffffffffffffffffffffffff809116918215613b8957160690565b83158015613fa6575b613f7c57613d07613d028585613c3b565b6135e7565b90600052602091600283526040600381600020019485600052846000209260005b888110613d39575050505050505055565b613d4c613d47828b86613c44565b613c54565b613d8188613d5f835164ffffffffff1690565b92015179ffffffffffffffffffffffffffffffffffffffffffffffffffff1690565b82613e055764ffffffffff613d968386613ca7565b1615801590613de1575b613db85790600192915b60281b178187015501613d28565b600486517f0b9752e0000000000000000000000000000000000000000000000000000000008152fd5b5079ffffffffffffffffffffffffffffffffffffffffffffffffffff811615613da0565b613e35613d477fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85018d88613c44565b613e6a613e5e8b83015179ffffffffffffffffffffffffffffffffffffffffffffffffffff1690565b915164ffffffffff1690565b64ffffffffff9182613e7c8c87613ca7565b161592831593613f4a575b8315613f3b575b8315613f11575b8315613ead575b505050613db8579060019291613daa565b79ffffffffffffffffffffffffffffffffffffffffffffffffffff929350613f069181613edf613ee793891688613b5e565b951690613b5e565b79ffffffffffffffffffffffffffffffffffffffffffffffffffff1690565b911611388080613e9c565b79ffffffffffffffffffffffffffffffffffffffffffffffffffff82811690861611159350613e95565b82811686821611159350613e8e565b925079ffffffffffffffffffffffffffffffffffffffffffffffffffff613f7384871686613cbd565b16151592613e87565b60046040517f3116ff5d000000000000000000000000000000000000000000000000000000008152fd5b5060058411613cf1565b6040810151613fbe81612f7e565b613fc781612f7e565b80613ff95750600160c08201511490811591613fe5575b50610efe57565b5164ffffffffff1660011415905038613fde565b80614005600392612f7e565b14614030575b60c08101511590811561401f5750610efe57565b5164ffffffffff1615905038613fde565b614059614054608083015173ffffffffffffffffffffffffffffffffffffffff1690565b614f73565b61400b565b9081549060ff8260501c169160601c9161407781612f7e565b8061408d57506001611b50930154913090615821565b8061409c600192959495612f7e565b036140c15790611b5092916140b960026001840154930154613761565b923090615749565b90600201549081800460011482151715612bde57611b509261414d565b80549192606083901c9260501c60ff166140f781612f7e565b8061410f575050916001611b50930154913090615821565b8061411e600192969396612f7e565b03614139576140b9611b509460026001850154940154613772565b90611b5093600261414b920154613772565b915b90919073ffffffffffffffffffffffffffffffffffffffff8116614199575090611b50915a917f00000000000000000000000000000000000000000000000000000000000000006158e3565b803b15614266576040517fa9059cbb000000000000000000000000000000000000000000000000000000006020820190815273ffffffffffffffffffffffffffffffffffffffff90941660248201526044810192909252600092839283906142048160648101611682565b51925af16142106156eb565b901561423c57805180614221575050565b816020806114e593614236950101910161580c565b61423c57565b60046040517ff1568f95000000000000000000000000000000000000000000000000000000008152fd5b60046040517f09ee12d5000000000000000000000000000000000000000000000000000000008152fd5b611b5090602073ffffffffffffffffffffffffffffffffffffffff82511691015190339061414d565b908160209103126102d2575190565b90614321906142d78382615212565b80547affffffffffffffffffffffffffffffffffffffffffffffffffffff164260d81b7fffffffffff00000000000000000000000000000000000000000000000000000016179055565b6040517f5d3b1d300000000000000000000000000000000000000000000000000000000081527f000000000000000000000000000000000000000000000000000000000000000060048201527f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff166024820152600360448201526207a12060648201526001608482015260208160a48160007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff165af1908115610cdd57600091614527575b5061442361441c826000526005602052604060002090565b5460ff1690565b6144fd577f3d94fecedaa4f90b8bd459797adb95f5bb11426025c5541390d9ccc1ad1b60a19161448b614460836000526005602052604060002090565b60017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b6144eb69ffffffffffffffffffff82166144af846000526005602052604060002090565b907fffffffffffffffffffffffffffffffffffffffffff00000000000000000000ff6affffffffffffffffffff0083549260081b169116179055565b604080519182526020820192909252a1565b60046040517ff9012132000000000000000000000000000000000000000000000000000000008152fd5b614548915060203d811161454e575b61454081836106a7565b8101906142b9565b38614404565b503d614536565b5460a01c60ff1660088110156110d55760030361456e57565b60046040517ff525e320000000000000000000000000000000000000000000000000000000008152fd5b5460a01c60ff1660088110156110d55760060361456e57565b5460a01c60ff1660088110156110d55760050361456e57565b5460a01c60ff1660088110156110d55760020361456e57565b5460a01c60ff1660088110156110d55760040361456e57565b5460a01c60ff1660088110156110d55760010361456e57565b919081101561369b5760071b0190565b91909164ffffffffff80809416911602918216918203612bde57565b91909179ffffffffffffffffffffffffffffffffffffffffffffffffffff80809416911601918211612bde57565b90916000926000928380925b8084106146885750505050565b9091929594614698878386614615565b96606088016146a96124b0826135fe565b614c0a575033965b8835906146c8826000526002602052604060002090565b9083614b9a5750600181015460501c73ffffffffffffffffffffffffffffffffffffffff16995b6020808201356003840180548210156125865761470b856145fc565b84546147209060b01c64ffffffffff16611572565b421015614b705761473a91614734916139db565b50613bfc565b9a61474860408094016135e7565b64ffffffffff92838216918215614b47576147a192918f61479c9261477561477a925164ffffffffff1690565b614625565b9f015179ffffffffffffffffffffffffffffffffffffffffffffffffffff1690565b613af8565b906147f48d610c926147e6846147c18b6000526003602052604060002090565b9073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b5460d01c64ffffffffff1690565b9160019889870193614812611572865464ffffffffff9060281c1690565b86821611614b1e578289939261488d6148929361483d886147c1896000526003602052604060002090565b907fff0000000000ffffffffffffffffffffffffffffffffffffffffffffffffffff7effffffffff000000000000000000000000000000000000000000000000000083549260d01b169116179055565b614641565b9e8c8160058a01805492508215600014614ae5575087167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0187169790505b88886148e2825460ff9060a81c1690565b614a90575b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff97947fa1b81c80064b5642431267c6e5e4aed96d5b588d231eeb1d3d0783fe2c59b2ff9488946149b7600286614949614a6b9d614a5d986115729e9a6152f2565b016149728561488d835479ffffffffffffffffffffffffffffffffffffffffffffffffffff1690565b79ffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffffffff0000000000000000000000000000000000000000000000000000825416179055565b6149fa6149d2336147c1886000526003602052604060002090565b6149728561488d835479ffffffffffffffffffffffffffffffffffffffffffffffffffff1690565b5193845233602085015273ffffffffffffffffffffffffffffffffffffffff909416604084015264ffffffffff909316606083015279ffffffffffffffffffffffffffffffffffffffffffffffffffff92909216608082015290819060a0820190565b0390a15464ffffffffff1690565b0191161015614a80575b50500192919061467b565b614a89916142c8565b3880614a75565b505090919250614aa8611572865464ffffffffff1690565b8688161015614abc579088929188886148e7565b600490517f34b3fb3b000000000000000000000000000000000000000000000000000000008152fd5b613235610c92917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff614b189501906139db565b966148d1565b600487517fd085f161000000000000000000000000000000000000000000000000000000008152fd5b600486517f3492aef6000000000000000000000000000000000000000000000000000000008152fd5b60046040517fb68c78dc000000000000000000000000000000000000000000000000000000008152fd5b99614bc0600183015473ffffffffffffffffffffffffffffffffffffffff9060501c1690565b73ffffffffffffffffffffffffffffffffffffffff808d16911603156146ef5760046040517ff5993428000000000000000000000000000000000000000000000000000000008152fd5b614c13906135fe565b966146b1565b73ffffffffffffffffffffffffffffffffffffffff818116614c40575050611b5090614fa0565b7f00000000000000000000000000000000000000000000000000000000000000001691823b156102d2576040517fda3e8ce400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9290921660048301523360248301523060448301526064820152906000908290608490829084905af18015610cdd57614cdb5750565b611b509061061d565b9160009260009260005b818110614cfa57505050565b614d08818385989798613aa0565b3594614d1e866000526002602052604060002090565b966006614d30895460ff9060a01c1690565b614d3981611d4a565b1061456e57614d56336147c1896000526003602052604060002090565b9788549279ffffffffffffffffffffffffffffffffffffffffffffffffffff84169360f81c8015614f23575b61255c5784614e65575091614e27817fc0b7cf12926534c2d86d0abb17d620a3a06e07a84b3b8156a4b21189222b16d29361488d614ddd6001809998015473ffffffffffffffffffffffffffffffffffffffff9060501c1690565b9c7f01000000000000000000000000000000000000000000000000000000000000007effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff825416179055565b60408051998a523360208b015279ffffffffffffffffffffffffffffffffffffffffffffffffffff929092169189019190915296606090a101614cee565b98919392906124b06001614e9292015473ffffffffffffffffffffffffffffffffffffffff9060501c1690565b73ffffffffffffffffffffffffffffffffffffffff8a16036121c657614e278160019561488d7fc0b7cf12926534c2d86d0abb17d620a3a06e07a84b3b8156a4b21189222b16d2957f01000000000000000000000000000000000000000000000000000000000000007effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff825416179055565b508315614d82565b73ffffffffffffffffffffffffffffffffffffffff163303614f4957565b60046040517f48f5c3ed000000000000000000000000000000000000000000000000000000008152fd5b73ffffffffffffffffffffffffffffffffffffffff1660005260046020526001604060002054036121c657565b34811115614fd25760046040517f8ffff980000000000000000000000000000000000000000000000000000000008152fd5b803411614fdc5750565b611b50905a903403337f00000000000000000000000000000000000000000000000000000000000000006158e3565b64ffffffffff9061501b816145fc565b5460b01c16421061502857565b60046040517ff9ad93f5000000000000000000000000000000000000000000000000000000008152fd5b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167404000000000000000000000000000000000000000017905560408051918252600460208301527fc1191e7178b58ad510709587719f39ec315fa79e81ee7ba5c5ef3c894e94a65191a1565b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167406000000000000000000000000000000000000000017905560408051918252600660208301527fc1191e7178b58ad510709587719f39ec315fa79e81ee7ba5c5ef3c894e94a65191a1565b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167407000000000000000000000000000000000000000017905560408051918252600760208301527fc1191e7178b58ad510709587719f39ec315fa79e81ee7ba5c5ef3c894e94a65191a1565b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167405000000000000000000000000000000000000000017905560408051918252600560208301527fc1191e7178b58ad510709587719f39ec315fa79e81ee7ba5c5ef3c894e94a65191a1565b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167402000000000000000000000000000000000000000017905560408051918252600260208301527fc1191e7178b58ad510709587719f39ec315fa79e81ee7ba5c5ef3c894e94a65191a1565b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167403000000000000000000000000000000000000000017905560408051918252600360208301527fc1191e7178b58ad510709587719f39ec315fa79e81ee7ba5c5ef3c894e94a65191a1565b6040519291906005016153048461066e565b64ffffffffff809216845273ffffffffffffffffffffffffffffffffffffffff60208501931683528054680100000000000000008110156106315761534e916001820181556139db565b9390936153a85751835492517fffffffffffffff000000000000000000000000000000000000000000000000009390931691161760289190911b78ffffffffffffffffffffffffffffffffffffffff000000000016179055565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b8115613b89570690565b60019391848101808211612bde578015613b8957820694600886811c9260ff908380838b161b945b61542f575b505050506154299061542083876139c7565b511791856139c7565b52929190565b9380615443878b9c9599969c9894986139c7565b5116156154915750505081906040516154688161168260208201948560209181520190565b5190209361547e61547885613791565b866153d7565b9788811c9483838b161b94909193615409565b9382995083965081955061540e565b805191821561553a576000925b808410615509575082151591826154eb575b5050156135f1577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b6155009192506154fa84613899565b906139c7565b511438806154bf565b6155138185615a17565b90818361552082876139c7565b51111561552e5750506154ad565b600101945090506154ad565b505050600090565b907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff81163303615618575081600052600560205260406000205460ff811661559e57505050565b69ffffffffffffffffffff9060081c1680600052600260205260406000209060026155ce835460ff9060a01c1690565b6155d781611d4a565b146155e3575b50505050565b6001926155f66155fb9261560d94615282565b6139ba565b51926000526005602052604060002090565b0155388080806155dd565b6040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff919091166024820152604490fd5b73ffffffffffffffffffffffffffffffffffffffff60005416330361568857565b60046040517f30cd7471000000000000000000000000000000000000000000000000000000008152fd5b60ff60015460b01c166156c157565b60046040517f1309a563000000000000000000000000000000000000000000000000000000008152fd5b3d15615744573d9067ffffffffffffffff8211610631576040519161573860207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601846106a7565b82523d6000602084013e565b606090565b91909392823b1561426657600094859485926040519260208401957ff242432a00000000000000000000000000000000000000000000000000000000875273ffffffffffffffffffffffffffffffffffffffff80921660248601521660448401526064830152608482015260a060a48201528160c482015260c481526157ce8161068a565b51925af16157da6156eb565b50156157e257565b60046040517f02f8f11e000000000000000000000000000000000000000000000000000000008152fd5b908160209103126102d257516135f1816104e6565b909192813b15614266576040519260208401947f23b872dd00000000000000000000000000000000000000000000000000000000865273ffffffffffffffffffffffffffffffffffffffff809216602486015216604484015260648301526064825260a082019282841067ffffffffffffffff851117610631576000809493819460405251925af16158b16156eb565b50156158b957565b60046040517fe0f5c508000000000000000000000000000000000000000000000000000000008152fd5b6158f882849395600080809781948294f11590565b6159025750505050565b73ffffffffffffffffffffffffffffffffffffffff16803b15615a1357604051937fd0e30db0000000000000000000000000000000000000000000000000000000008552838560048186865af1938415610cdd576159bb95602095615a00575b506040518096819582947fa9059cbb000000000000000000000000000000000000000000000000000000008452600484016020909392919373ffffffffffffffffffffffffffffffffffffffff60408201951681520152565b03925af18015610cdd576159d2575b8080806155dd565b6159f29060203d81116159f9575b6159ea81836106a7565b81019061580c565b50386159ca565b503d6159e0565b80610cd1615a0d9261061d565b38615962565b8280fd5b90808216911860011c8101809111612bde579056fea2646970667358221220bf93bd80b91da28dc011ba8a77ed5bfbd550a6ba0168ccc0f3dc76a965b0552364736f6c63430008140033000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28af398995b04c28e9951adb9721ef74c74f93e6a478f39e7e0777be13527e7ef00000000000000000000000000000000000000000000000000000000000002de000000000000000000000000271682deb8c4e0901d1a1550ad2e64d568e69909000000000000000000000000b5a9e5a319c7fda551a30be592c77394bf935c6f000000000000000000000000b5a9e5a319c7fda551a30be592c77394bf935c6f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ea4af05656c17b90f4d64add29e1d
Deployed Bytecode
0x6080604052600436101561001257600080fd5b60003560e01c8063030932bb146102c25780630d64d5a6146102bd5780631e9f1a82146102b85780631fe543e3146102b3578063208b3d34146102ae57806323452b9c146102a95780632a6a4eb8146102a45780632bb5a9e61461029f57806331fe74a91461029a57806336566f061461029557806339a2eb2a146102905780633b6cb153146102545780633e5675391461028b57806340e58ee51461028657806349890e15146102815780634d2c53cd1461027c578063534fff0e146102775780635a195d19146102725780635b6ac0111461026d5780635c975abb146102685780635cb6dfff146102635780635d4bc0ce1461025e57806364df049e1461025957806365d697f7146102545780636b1426a41461024f5780636b7e4e3f1461024a5780636f30d7b5146102455780637200b829146102405780637762df251461023b5780637b154140146102365780638da5cb5b1461023157806398753c461461022c578063a17be15414610227578063a72844ba14610222578063ac68a7481461021d578063c0b6f56114610218578063cc30779514610213578063d1d06b2e1461020e578063d3549ebd14610209578063e521cb9214610204578063ea9bf39d146101ff578063f23a6e61146101fa5763f54a6f83146101f557600080fd5b613546565b6134a1565b613467565b613360565b6132aa565b613149565b613032565b612e7d565b612be3565b612aec565b612a37565b6129f8565b6129a6565b61277f565b61272d565b6125be565b61223d565b612073565b611f94565b611734565b611ebe565b611df3565b611cdb565b611c97565b611bbb565b611b52565b6119e2565b61199a565b61195f565b61186c565b61176e565b61148a565b611344565b6112a8565b6111f0565b6110e9565b610fcd565b6107aa565b610700565b6104f0565b61036b565b6102d7565b60009103126102d257565b600080fd5b346102d25760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257602060405167ffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000002de168152f35b9181601f840112156102d25782359167ffffffffffffffff83116102d2576020808501948460071b0101116102d257565b60207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d25760043567ffffffffffffffff81116102d2576103b590369060040161033a565b600260ff60015460a81c161461048b5761043a79ffffffffffffffffffffffffffffffffffffffffffffffffffff916104449361042d75020000000000000000000000000000000000000000007fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff6001541617600155565b6104356156b2565b61466f565b9190911690614c19565b61048975010000000000000000000000000000000000000000007fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff6001541617600155565b005b60046040517f1bbee726000000000000000000000000000000000000000000000000000000008152fd5b9181601f840112156102d25782359167ffffffffffffffff83116102d2576020808501948460051b0101116102d257565b801515036102d257565b346102d2576040807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257600490813567ffffffffffffffff81116102d25761054190369084016104b5565b916024359361054f856104e6565b610557615667565b60005b8481106105985750507fcb2fef16ee9f3ea43e174daf88ffcdc8beee4ad884c7570093d998d71058698793610593915193849384613b8e565b0390a1005b600190600087156105e6575060ff825b73ffffffffffffffffffffffffffffffffffffffff6105c8848a8a613aa0565b356105d281611b27565b16600052846020521684600020550161055a565b60ff906105a8565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b67ffffffffffffffff811161063157604052565b6105ee565b6080810190811067ffffffffffffffff82111761063157604052565b60e0810190811067ffffffffffffffff82111761063157604052565b6040810190811067ffffffffffffffff82111761063157604052565b610100810190811067ffffffffffffffff82111761063157604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761063157604052565b67ffffffffffffffff81116106315760051b60200190565b346102d25760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d25760243567ffffffffffffffff81116102d257366023820112156102d25780600401359061075b826106e8565b9061076960405192836106a7565b82825260209260248484019160051b830101913683116102d257602401905b82821061079b5761048984600435615542565b81358152908401908401610788565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6020813601126102d25767ffffffffffffffff600435116102d25761010090600435360301126102d257600260ff60015460a81c161461048b5761084a75020000000000000000000000000000000000000000007fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff6001541617600155565b6108526156b2565b6108606004356004016135e7565b64ffffffffff81168062015180420111908115610fbe575b50610f945761088b6084600435016135f4565b600654908160f01c61ffff821603610f6a576108ab60a4600435016135fe565b9073ffffffffffffffffffffffffffffffffffffffff8216610f5c575b6108dc60c460043501600435600401613608565b80939150158015610f52575b610f285769ffffffffffffffffffff9461093a866001818816011669ffffffffffffffffffff167fffffffffffffffffffffffffffffffffffffffffffff000000000000000000006006541617600655565b85600181871601166000526002602052604060002093600485016000526020600020906000906000926000906000915b838310610b0057505050600487015561098290614fa0565b64ffffffffff6109966044600435016135e7565b911664ffffffffff82168111908115610af5575b50610acb576001936109d76109c960e4600435016004356004016137f2565b90848b89818d160116613ce8565b740100000000000000000000000000000000000000006109fb602460043501613846565b610a096064600435016135e7565b9460b01b9060a81b33171717865560f01b9260501b9160281b1717179101557fc1191e7178b58ad510709587719f39ec315fa79e81ee7ba5c5ef3c894e94a65160405180610a6c8560018187160116826020600191939293604081019481520152565b0390a1610ab475010000000000000000000000000000000000000000007fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff6001541617600155565b6040519082166001019091168152602090f35b0390f35b60046040517f804a1e02000000000000000000000000000000000000000000000000000000008152fd5b60c8915011386109aa565b610b29610b2484610b1e60c460049a979a3501600435600401613608565b9061368b565b6136ae565b9560ff610b3a606089015160ff1690565b921660ff831610610efe57610b4e87613fb0565b604087015196610b5d88612f7e565b805164ffffffffff1694610b88608083015173ffffffffffffffffffffffffffffffffffffffff1690565b60c060a084015193015192610b9c8b612f7e565b8a610ce25773ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000ea4af05656c17b90f4d64add29e1d163b156102d2576040517fcda20f0b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83166004820152336024820152306044820152606481018290529560008780608481015b03818373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000ea4af05656c17b90f4d64add29e1d165af1968715610cdd5789600295610c979260019a610cc4575b505b6137d9565b9b8c829a600389028b019560601b9360581b9260501b9160281b171717178255858201550155019161096a565b80610cd1610cd79261061d565b806102c7565b38610c90565b613785565b610ceb8b612f7e565b60038b03610da557610d0464ffffffffff891685613772565b9573ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000ea4af05656c17b90f4d64add29e1d163b156102d2576040517fda3e8ce400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8416600482015233602482015230604482015260648101979097526000878060848101610c3d565b9198610db58b9692949596612f7e565b60028b03610deb5791600195949391610c9789610de5600296610ddf64ffffffffff84168a613772565b9061379f565b9c6137d9565b9891610e0364ffffffffff8997969593971685613772565b9573ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000ea4af05656c17b90f4d64add29e1d163b156102d2576040517fe62edc3500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841660048201523360248201523060448201526064810183905260848101979097526000878060a4810103818373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000ea4af05656c17b90f4d64add29e1d165af1968715610cdd5789600295610c979260019a610cc457506137d9565b60046040517f5f12e2ee000000000000000000000000000000000000000000000000000000008152fd5b60046040517fab13062d000000000000000000000000000000000000000000000000000000008152fd5b5060c883116108e8565b610f6582614f73565b6108c8565b60046040517f4929acd7000000000000000000000000000000000000000000000000000000008152fd5b60046040517fce8f4bfd000000000000000000000000000000000000000000000000000000008152fd5b905062093a8042011038610878565b346102d2576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126110da57611005615667565b60015460ff8160a01c1660038110156110d55780156110ab578061102a6001926111e6565b14611080575b507fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff600154166001557f8eca980489e87f7dba4f26917aa4bfc906eb3f2b4f7b4b9fd0ff2b8bb3e21ae38180a180f35b7fffffffffffffffffffffffff00000000000000000000000000000000000000001660015538611030565b60046040517fccf69db7000000000000000000000000000000000000000000000000000000008152fd5b6111b7565b80fd5b61ffff8116036102d257565b346102d25760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257600435611124816110dd565b61112c615667565b61ffff8116906109c48211610f6a577fede4aee4284b8033b84c1aadcc51b229a4e46e6b42ab40092e237f07508b4626916020917dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffff0000000000000000000000000000000000000000000000000000000000006006549260f01b16911617600655604051908152a1005b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600311156110d557565b346102d25760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d25760ff60015460a01c1660405160038210156110d5576020918152f35b60208082019080835283518092528060408094019401926000905b83821061126557505050505090565b8451805164ffffffffff16875283015179ffffffffffffffffffffffffffffffffffffffffffffffffffff16868401529485019493820193600190910190611256565b346102d2576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d25760043560005260028152600360406000200180546112f5816106e8565b9161130360405193846106a7565b8183526000908152838120938084015b8383106113285760405180610ac7878261123b565b600182819261133689613bfc565b815201960192019194611313565b346102d25760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d25761137b615667565b60015460ff8160b01c16600014611417575060015460ff8160b01c16156113ed577fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff166001557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6020604051338152a1005b60046040517f6cd60201000000000000000000000000000000000000000000000000000000008152fd5b7fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff760100000000000000000000000000000000000000000000916114596156b2565b16176001557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a1005b346102d2576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d2576114d86114d36004356000526005602052604060002090565b613850565b6114e96114e58251151590565b1590565b61170a576115156115068383015169ffffffffffffffffffff1690565b69ffffffffffffffffffff1690565b9161152a836000526002602052604060002090565b9261153484614555565b61153e8185615052565b6004840191825493611583600561157c61157261156361155d8a613899565b896138c6565b505460281c64ffffffffff1690565b64ffffffffff1690565b97016138e2565b80519361158f8561396b565b9460005b8181106116da57506115a76115ad91613899565b866139c7565b51916115c36115be8460081c613791565b61396b565b976115cd8161396b565b9760005b8281106116b657505050604080940151916000526002855260068460002001978860005285600020936000935b8b851061160a578b8b55005b89946116346116508a6116228d978761162e976153e1565b908095929791996154a0565b896139c7565b51015173ffffffffffffffffffffffffffffffffffffffff1690565b61165e6001840180996154a0565b60a81b179060b01b179087015586516116ae816116828b8201948560209181520190565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018352826106a7565b5190206115fe565b806116c9611572611563600194866138c6565b6116d3828d6139c7565b52016115d1565b806116f96115726116ed600194886139c7565b515164ffffffffff1690565b611703828a6139c7565b5201611593565b60046040517f1b71a84c000000000000000000000000000000000000000000000000000000008152fd5b346102d25760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257602060405160c88152f35b346102d2576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126110da576117a6615667565b60ff60015460a01c1660038110156110d557600203611842577fffffffffffffffffffffffff000000000000000000000000000000000000000081541681556118127fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff60015416600155565b604051600081527f3edd90e7770f06fafde38004653b33870066c33bfc923ff6102acd601f85dfbc90602090a180f35b60046040517f045c5122000000000000000000000000000000000000000000000000000000008152fd5b346102d25760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257600435600260ff60015460a81c161461048b57610444906118f775020000000000000000000000000000000000000000007fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff6001541617600155565b6118ff6156b2565b80600052600260205260406000206119168161500b565b805464ffffffffff61192c818360b01c166137ac565b16421061193a575b506150c2565b73ffffffffffffffffffffffffffffffffffffffff6119599116614f2b565b38611934565b346102d25760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d25760206040516109c48152f35b346102d25760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257602069ffffffffffffffffffff60065416604051908152f35b346102d25760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257600435600190600260ff835460a81c161461048b57611a6b75020000000000000000000000000000000000000000007fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff6001541617600155565b611a736156b2565b806000526002602052611a94604060002091611a8e83614598565b82615132565b6004810173ffffffffffffffffffffffffffffffffffffffff815492541660005b838110611b015761048975010000000000000000000000000000000000000000007fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff6001541617600155565b80611b21611b108793866138c6565b508464ffffffffff825416916140de565b01611ab5565b73ffffffffffffffffffffffffffffffffffffffff8116036102d257565b3590611b5082611b27565b565b346102d25760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d25773ffffffffffffffffffffffffffffffffffffffff600435611ba281611b27565b1660005260046020526020604060002054604051908152f35b346102d2576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126110da57611bf3615667565b60015460ff8160a01c1660038110156110d557611c6d577fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674020000000000000000000000000000000000000000176001557f3ff05a45e46337fa1cbf20996d2eeb927280bce099f37252bcca1040609604ec8180a180f35b60046040517f74ed79ae000000000000000000000000000000000000000000000000000000008152fd5b346102d25760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257602060ff60015460b01c166040519015158152f35b346102d25760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d2576004356000526005602052606060406000206001815491015469ffffffffffffffffffff6040519260ff81161515845260081c1660208301526040820152f35b600811156110d557565b9893969a999597919a9290926101408a019b73ffffffffffffffffffffffffffffffffffffffff8095168b5260088110156110d5576101209979ffffffffffffffffffffffffffffffffffffffffffffffffffff9961ffff988d9560609460208801521515604087015264ffffffffff958694858094169101521660808d01521660a08b01521660c08901521660e08701521661010085015216910152565b346102d25760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257600435600052600260205260406000208054610ac7611e636002600185015494015479ffffffffffffffffffffffffffffffffffffffffffffffffffff1690565b60405193849373ffffffffffffffffffffffffffffffffffffffff9164ffffffffff928160f01c93818360501c169381808560281c169416928160d81c928260b01c169160ff8160a81c169160ff8260a01c1691168b611d54565b346102d25760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257602073ffffffffffffffffffffffffffffffffffffffff60065460501c16604051908152f35b60208082019080835283518092528060408094019401926000905b838210611f3d57505050505090565b8451805173ffffffffffffffffffffffffffffffffffffffff168752808401511515878501528082015160ff168783015260609081015164ffffffffff169087015260809095019493820193600190910190611f2e565b346102d2576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d2576004356000526002815260409060068260002001805490611fe4826106e8565b92611ff1855194856106a7565b82845260009182528082208185015b84841061201457865180610ac78882611f13565b6001838192895161202481610636565b64ffffffffff865473ffffffffffffffffffffffffffffffffffffffff8116835260ff808260a01c161515868501528160a81c168d84015260b01c166060820152815201920193019290612000565b60407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d25767ffffffffffffffff6004358181116102d2576120be9036906004016104b5565b916024359081116102d2576120d790369060040161033a565b929091600260ff60015460a81c161461048b5761214c916121449161213775020000000000000000000000000000000000000000007fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff6001541617600155565b61213f6156b2565b614ce4565b93909261466f565b9073ffffffffffffffffffffffffffffffffffffffff809116908316036121c65779ffffffffffffffffffffffffffffffffffffffffffffffffffff9081169216828111156121a35791610444920390339061414d565b8281106121b3575b505050610444565b6121be920390614c19565b3880806121ab565b60046040517ff5993428000000000000000000000000000000000000000000000000000000008152fd5b60207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8201126102d2576004359067ffffffffffffffff82116102d257612239916004016104b5565b9091565b346102d25761224b366121f0565b90600260ff60015460a81c161461048b576122a175020000000000000000000000000000000000000000007fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff6001541617600155565b6122a96156b2565b6122b16139f3565b9160005b81811061231a5783602081015161230b5761048975010000000000000000000000000000000000000000007fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff6001541617600155565b61231490614290565b80610444565b612325818385613a0c565b61233a81356000526002602052604060002090565b90600461234c835460ff9060a01c1690565b61235581611d4a565b036125b0575b6123686020820182613a4c565b9092600681015460005b8381106123bc57505050917f0d0ab4a45afc0276ae825be9eeb4552011b19aad5c92b4bb782f3ca0356fedc5916123b3600195946040519384933584613ab0565b0390a1016122b5565b6123c7818588613aa0565b3582811015612586576123dd90600685016139db565b509081549160ff8360a01c1661255c5760019261246861245f8e9361241873ffffffffffffffffffffffffffffffffffffffff809516614f2b565b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001781555460a81c60ff1690565b600488016138c6565b50908461247a835460ff9060501c1690565b61248381612f7e565b111561254a57815460601c906124c96124b0855173ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1690565b908216036124f057506002915001546124e760208d0191825161379f565b90525b01612372565b9061251d60029260208501948551612526579073ffffffffffffffffffffffffffffffffffffffff169052565b015490526124ea565b61252f81614290565b9073ffffffffffffffffffffffffffffffffffffffff169052565b506125579150339061405e565b6124ea565b60046040517f969bf728000000000000000000000000000000000000000000000000000000008152fd5b60046040517f63df8171000000000000000000000000000000000000000000000000000000008152fd5b6125b9826145b1565b61235b565b346102d25760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257600154600160ff8260a01c16612602816111e6565b036127035773ffffffffffffffffffffffffffffffffffffffff1633036126d957600080547fffffffffffffffffffffffff0000000000000000000000000000000000000000163317905561267a7fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff60015416600155565b6126a77fffffffffffffffffffffffff000000000000000000000000000000000000000060015416600155565b6040513381527f3edd90e7770f06fafde38004653b33870066c33bfc923ff6102acd601f85dfbc908060208101610593565b60046040517fafdcfb92000000000000000000000000000000000000000000000000000000008152fd5b60046040517f5e4f2826000000000000000000000000000000000000000000000000000000008152fd5b346102d25760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257602073ffffffffffffffffffffffffffffffffffffffff60015416604051908152f35b346102d25760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d2576004803560243590600260ff60015460a81c161461297d5761280b75020000000000000000000000000000000000000000007fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff6001541617600155565b6128136156b2565b612827816000526002602052604060002090565b8054849060a01c60ff1661283a81611d4a565b0361296f575b6006810180548410156129465783612857916139db565b50805460ff8160a01c1661291d57917fd53b67ba94a5d6268d11caa5d2693557779404ed02fc9825d86d2894d29cb8fd956128b16128b89361241873ffffffffffffffffffffffffffffffffffffffff6128c09716614f2b565b91016138c6565b50339061405e565b60408051918252602082019290925290819081015b0390a161048975010000000000000000000000000000000000000000007fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff6001541617600155565b856040517f969bf728000000000000000000000000000000000000000000000000000000008152fd5b846040517f63df8171000000000000000000000000000000000000000000000000000000008152fd5b612978816145b1565b612840565b826040517f1bbee726000000000000000000000000000000000000000000000000000000008152fd5b346102d25760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257602073ffffffffffffffffffffffffffffffffffffffff60005416604051908152f35b346102d25760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257602060065460f01c604051908152f35b346102d25760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d2576060612aac602435612a7781611b27565b600435600052600360205260406000209073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b546040519079ffffffffffffffffffffffffffffffffffffffffffffffffffff8116825264ffffffffff8160d01c16602083015260f81c15156040820152f35b346102d25760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257600435600260ff60015460a81c161461048b57612b7375020000000000000000000000000000000000000000007fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff6001541617600155565b612b7b6156b2565b806000526002602052604060002090612b93826145ca565b815460d81c620151808101809111612bde574210612bb457610444916150c2565b60046040517ff4c0ca6e000000000000000000000000000000000000000000000000000000008152fd5b613732565b346102d25760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257600435600260ff60015460a81c161461048b577fa1f87f32d0f17fab0242ca800d736293de8988c14b27747e218cf13d5c249f5390612c8c75020000000000000000000000000000000000000000007fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff6001541617600155565b612c946156b2565b80612ca9816000526002602052604060002090565b612cb2816145e3565b612d9a612cd3825473ffffffffffffffffffffffffffffffffffffffff1690565b9173ffffffffffffffffffffffffffffffffffffffff83163303612e51575b612de66002820191612ddf612d21845479ffffffffffffffffffffffffffffffffffffffffffffffffffff1690565b93612dc26001840191612d6f612d4b612d45612d3e865460f01c90565b61ffff1690565b89613af8565b79ffffffffffffffffffffffffffffffffffffffffffffffffffff61271091160490565b97889779ffffffffffffffffffffffffffffffffffffffffffffffffffff998a9103169b8c966151a2565b7fffffffffffff00000000000000000000000000000000000000000000000000008154169055565b5460501c73ffffffffffffffffffffffffffffffffffffffff1690565b948561414d565b1680612e23575b50506040805191825279ffffffffffffffffffffffffffffffffffffffffffffffffffff909216602082015290819081016128d5565b600654612e4a929060501c73ffffffffffffffffffffffffffffffffffffffff169061414d565b3880612ded565b612e78612e7360005473ffffffffffffffffffffffffffffffffffffffff1690565b614f2b565b612cf2565b346102d25760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257600435612eb881611b27565b612ec0615667565b60015460ff8160a01c1660038110156110d557611c6d577fffffffffffffffffffffff0000000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff82161774010000000000000000000000000000000000000000176001557fb86c75c9bffca616b2d314cc914f7c3f1d174255b16b941c3f3ededee276d5ef90610593906040805133815273ffffffffffffffffffffffffffffffffffffffff909216602083015290918291820190565b600411156110d557565b60208082019080835283518092528060408094019401926000905b838210612fb257505050505090565b9091929394855164ffffffffff8082511683528582015116858301528281015160048110156110d5578284015260608181015160ff169083015260808082015173ffffffffffffffffffffffffffffffffffffffff169083015260a0808201519083015260c0908101519082015260e00194830193929160010190612fa3565b346102d2576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257600435600052600280825260409160048360002001805491613083836106e8565b93613090865195866106a7565b8385526000928352818320908286015b8585106130b457875180610ac78982612f88565b6003846001928a516130c581610652565b613129875464ffffffffff80821684528160281c16858401528d6130f360ff91828460501c16908601613bf0565b6131096060918360581c168286019060ff169052565b1c608083019073ffffffffffffffffffffffffffffffffffffffff169052565b8487015460a08201528587015460c08201528152019301940193916130a0565b346102d25760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257600435600260ff60015460a81c161461048b576131d075020000000000000000000000000000000000000000007fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff6001541617600155565b6131d86156b2565b6131ec816000526002602052604060002090565b6005810180549081156132805761324661157261324161323564ffffffffff9461322f61322961156360048b016132238154613899565b906138c6565b97613899565b906139db565b505464ffffffffff1690565b6137c3565b911611613280576104449161325a8261500b565b61327b612e73835473ffffffffffffffffffffffffffffffffffffffff1690565b6142c8565b60046040517f9358a89d000000000000000000000000000000000000000000000000000000008152fd5b346102d2576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257600435600052600281526040906132f6600583600020016138e2565b8251928284938401908085528351809252808386019401926000905b83821061331f5786860387f35b8451805164ffffffffff16875283015173ffffffffffffffffffffffffffffffffffffffff1686840152879650948501949382019360019190910190613312565b346102d25760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d25760043561339b81611b27565b6133a3615667565b73ffffffffffffffffffffffffffffffffffffffff811690811561343d577fc1b5345cce283376356748dc57f2dfa7120431d016fc7ca9ba641bc65f91411d916020917fffff0000000000000000000000000000000000000000ffffffffffffffffffff7dffffffffffffffffffffffffffffffffffffffff000000000000000000006006549260501b16911617600655604051908152a1005b60046040517f3106a0c7000000000000000000000000000000000000000000000000000000008152fd5b346102d25760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257602060405160058152f35b346102d25760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d2576134db600435611b27565b6134e6602435611b27565b60843567ffffffffffffffff8082116102d257366023830112156102d25781600401359081116102d257369101602401116102d2576040517ff23a6e61000000000000000000000000000000000000000000000000000000008152602090f35b346102d257613554366121f0565b600260ff60015460a81c161461048b576135cc79ffffffffffffffffffffffffffffffffffffffffffffffffffff916104449361213775020000000000000000000000000000000000000000007fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff6001541617600155565b9190911690339061414d565b64ffffffffff8116036102d257565b356135f1816135d8565b90565b356135f1816110dd565b356135f181611b27565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156102d2570180359067ffffffffffffffff82116102d2576020019160e08202360383136102d257565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b919081101561369b5760e0020190565b61365c565b359060ff821682036102d257565b60e0813603126102d257604051906136c582610652565b80356136d0816135d8565b825260208101356136e0816135d8565b602083015260408101359060048210156102d25760c0916040840152613708606082016136a0565b606084015261371960808201611b45565b608084015260a081013560a0840152013560c082015290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9081156001838004141715612bde57565b81810292918115918404141715612bde57565b6040513d6000823e3d90fd5b9060018201809211612bde57565b91908201809211612bde57565b90610e1064ffffffffff80931601918211612bde57565b90600164ffffffffff80931601918211612bde57565b91909164ffffffffff80809416911601918211612bde57565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156102d2570180359067ffffffffffffffff82116102d257602001918160061b360383136102d257565b356135f1816104e6565b906040516060810181811067ffffffffffffffff8211176106315760405260406001829469ffffffffffffffffffff815460ff81161515865260081c1660208501520154910152565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8201918211612bde57565b805482101561369b576000526003602060002091020190600090565b9081546138ee816106e8565b926040936138fe855191826106a7565b828152809460208092019260005281600020906000935b85851061392457505050505050565b600184819284516139348161066e565b73ffffffffffffffffffffffffffffffffffffffff875464ffffffffff8116835260281c1683820152815201930194019391613915565b90613975826106e8565b61398260405191826106a7565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06139b082946106e8565b0190602036910137565b80511561369b5760200190565b805182101561369b5760209160051b010190565b805482101561369b5760005260206000200190600090565b60405190613a008261066e565b60006020838281520152565b919081101561369b5760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc1813603018212156102d2570190565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156102d2570180359067ffffffffffffffff82116102d257602001918160051b360383136102d257565b919081101561369b5760051b0190565b908152604060208201528260408201527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83116102d25760609260051b809284830137010190565b919079ffffffffffffffffffffffffffffffffffffffffffffffffffff8080941691169283820216928184041490151715612bde57565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b9079ffffffffffffffffffffffffffffffffffffffffffffffffffff809116918215613b8957160490565b613b2f565b6040808252810183905292939291606083019060005b818110613bb957505060209150931515910152565b909160019073ffffffffffffffffffffffffffffffffffffffff8535613bde81611b27565b16815260209485019401929101613ba4565b60048210156110d55752565b90604051613c098161066e565b915464ffffffffff8116835260281c79ffffffffffffffffffffffffffffffffffffffffffffffffffff166020830152565b901561369b5790565b919081101561369b5760061b0190565b6040813603126102d257602060405191613c6d8361066e565b8035613c78816135d8565b8352013579ffffffffffffffffffffffffffffffffffffffffffffffffffff811681036102d257602082015290565b9064ffffffffff809116918215613b8957160690565b9079ffffffffffffffffffffffffffffffffffffffffffffffffffff809116918215613b8957160690565b83158015613fa6575b613f7c57613d07613d028585613c3b565b6135e7565b90600052602091600283526040600381600020019485600052846000209260005b888110613d39575050505050505055565b613d4c613d47828b86613c44565b613c54565b613d8188613d5f835164ffffffffff1690565b92015179ffffffffffffffffffffffffffffffffffffffffffffffffffff1690565b82613e055764ffffffffff613d968386613ca7565b1615801590613de1575b613db85790600192915b60281b178187015501613d28565b600486517f0b9752e0000000000000000000000000000000000000000000000000000000008152fd5b5079ffffffffffffffffffffffffffffffffffffffffffffffffffff811615613da0565b613e35613d477fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85018d88613c44565b613e6a613e5e8b83015179ffffffffffffffffffffffffffffffffffffffffffffffffffff1690565b915164ffffffffff1690565b64ffffffffff9182613e7c8c87613ca7565b161592831593613f4a575b8315613f3b575b8315613f11575b8315613ead575b505050613db8579060019291613daa565b79ffffffffffffffffffffffffffffffffffffffffffffffffffff929350613f069181613edf613ee793891688613b5e565b951690613b5e565b79ffffffffffffffffffffffffffffffffffffffffffffffffffff1690565b911611388080613e9c565b79ffffffffffffffffffffffffffffffffffffffffffffffffffff82811690861611159350613e95565b82811686821611159350613e8e565b925079ffffffffffffffffffffffffffffffffffffffffffffffffffff613f7384871686613cbd565b16151592613e87565b60046040517f3116ff5d000000000000000000000000000000000000000000000000000000008152fd5b5060058411613cf1565b6040810151613fbe81612f7e565b613fc781612f7e565b80613ff95750600160c08201511490811591613fe5575b50610efe57565b5164ffffffffff1660011415905038613fde565b80614005600392612f7e565b14614030575b60c08101511590811561401f5750610efe57565b5164ffffffffff1615905038613fde565b614059614054608083015173ffffffffffffffffffffffffffffffffffffffff1690565b614f73565b61400b565b9081549060ff8260501c169160601c9161407781612f7e565b8061408d57506001611b50930154913090615821565b8061409c600192959495612f7e565b036140c15790611b5092916140b960026001840154930154613761565b923090615749565b90600201549081800460011482151715612bde57611b509261414d565b80549192606083901c9260501c60ff166140f781612f7e565b8061410f575050916001611b50930154913090615821565b8061411e600192969396612f7e565b03614139576140b9611b509460026001850154940154613772565b90611b5093600261414b920154613772565b915b90919073ffffffffffffffffffffffffffffffffffffffff8116614199575090611b50915a917f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26158e3565b803b15614266576040517fa9059cbb000000000000000000000000000000000000000000000000000000006020820190815273ffffffffffffffffffffffffffffffffffffffff90941660248201526044810192909252600092839283906142048160648101611682565b51925af16142106156eb565b901561423c57805180614221575050565b816020806114e593614236950101910161580c565b61423c57565b60046040517ff1568f95000000000000000000000000000000000000000000000000000000008152fd5b60046040517f09ee12d5000000000000000000000000000000000000000000000000000000008152fd5b611b5090602073ffffffffffffffffffffffffffffffffffffffff82511691015190339061414d565b908160209103126102d2575190565b90614321906142d78382615212565b80547affffffffffffffffffffffffffffffffffffffffffffffffffffff164260d81b7fffffffffff00000000000000000000000000000000000000000000000000000016179055565b6040517f5d3b1d300000000000000000000000000000000000000000000000000000000081527f8af398995b04c28e9951adb9721ef74c74f93e6a478f39e7e0777be13527e7ef60048201527f00000000000000000000000000000000000000000000000000000000000002de67ffffffffffffffff166024820152600360448201526207a12060648201526001608482015260208160a48160007f000000000000000000000000271682deb8c4e0901d1a1550ad2e64d568e6990973ffffffffffffffffffffffffffffffffffffffff165af1908115610cdd57600091614527575b5061442361441c826000526005602052604060002090565b5460ff1690565b6144fd577f3d94fecedaa4f90b8bd459797adb95f5bb11426025c5541390d9ccc1ad1b60a19161448b614460836000526005602052604060002090565b60017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b6144eb69ffffffffffffffffffff82166144af846000526005602052604060002090565b907fffffffffffffffffffffffffffffffffffffffffff00000000000000000000ff6affffffffffffffffffff0083549260081b169116179055565b604080519182526020820192909252a1565b60046040517ff9012132000000000000000000000000000000000000000000000000000000008152fd5b614548915060203d811161454e575b61454081836106a7565b8101906142b9565b38614404565b503d614536565b5460a01c60ff1660088110156110d55760030361456e57565b60046040517ff525e320000000000000000000000000000000000000000000000000000000008152fd5b5460a01c60ff1660088110156110d55760060361456e57565b5460a01c60ff1660088110156110d55760050361456e57565b5460a01c60ff1660088110156110d55760020361456e57565b5460a01c60ff1660088110156110d55760040361456e57565b5460a01c60ff1660088110156110d55760010361456e57565b919081101561369b5760071b0190565b91909164ffffffffff80809416911602918216918203612bde57565b91909179ffffffffffffffffffffffffffffffffffffffffffffffffffff80809416911601918211612bde57565b90916000926000928380925b8084106146885750505050565b9091929594614698878386614615565b96606088016146a96124b0826135fe565b614c0a575033965b8835906146c8826000526002602052604060002090565b9083614b9a5750600181015460501c73ffffffffffffffffffffffffffffffffffffffff16995b6020808201356003840180548210156125865761470b856145fc565b84546147209060b01c64ffffffffff16611572565b421015614b705761473a91614734916139db565b50613bfc565b9a61474860408094016135e7565b64ffffffffff92838216918215614b47576147a192918f61479c9261477561477a925164ffffffffff1690565b614625565b9f015179ffffffffffffffffffffffffffffffffffffffffffffffffffff1690565b613af8565b906147f48d610c926147e6846147c18b6000526003602052604060002090565b9073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b5460d01c64ffffffffff1690565b9160019889870193614812611572865464ffffffffff9060281c1690565b86821611614b1e578289939261488d6148929361483d886147c1896000526003602052604060002090565b907fff0000000000ffffffffffffffffffffffffffffffffffffffffffffffffffff7effffffffff000000000000000000000000000000000000000000000000000083549260d01b169116179055565b614641565b9e8c8160058a01805492508215600014614ae5575087167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0187169790505b88886148e2825460ff9060a81c1690565b614a90575b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff97947fa1b81c80064b5642431267c6e5e4aed96d5b588d231eeb1d3d0783fe2c59b2ff9488946149b7600286614949614a6b9d614a5d986115729e9a6152f2565b016149728561488d835479ffffffffffffffffffffffffffffffffffffffffffffffffffff1690565b79ffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffffffff0000000000000000000000000000000000000000000000000000825416179055565b6149fa6149d2336147c1886000526003602052604060002090565b6149728561488d835479ffffffffffffffffffffffffffffffffffffffffffffffffffff1690565b5193845233602085015273ffffffffffffffffffffffffffffffffffffffff909416604084015264ffffffffff909316606083015279ffffffffffffffffffffffffffffffffffffffffffffffffffff92909216608082015290819060a0820190565b0390a15464ffffffffff1690565b0191161015614a80575b50500192919061467b565b614a89916142c8565b3880614a75565b505090919250614aa8611572865464ffffffffff1690565b8688161015614abc579088929188886148e7565b600490517f34b3fb3b000000000000000000000000000000000000000000000000000000008152fd5b613235610c92917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff614b189501906139db565b966148d1565b600487517fd085f161000000000000000000000000000000000000000000000000000000008152fd5b600486517f3492aef6000000000000000000000000000000000000000000000000000000008152fd5b60046040517fb68c78dc000000000000000000000000000000000000000000000000000000008152fd5b99614bc0600183015473ffffffffffffffffffffffffffffffffffffffff9060501c1690565b73ffffffffffffffffffffffffffffffffffffffff808d16911603156146ef5760046040517ff5993428000000000000000000000000000000000000000000000000000000008152fd5b614c13906135fe565b966146b1565b73ffffffffffffffffffffffffffffffffffffffff818116614c40575050611b5090614fa0565b7f00000000000000000000000000000000000ea4af05656c17b90f4d64add29e1d1691823b156102d2576040517fda3e8ce400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9290921660048301523360248301523060448301526064820152906000908290608490829084905af18015610cdd57614cdb5750565b611b509061061d565b9160009260009260005b818110614cfa57505050565b614d08818385989798613aa0565b3594614d1e866000526002602052604060002090565b966006614d30895460ff9060a01c1690565b614d3981611d4a565b1061456e57614d56336147c1896000526003602052604060002090565b9788549279ffffffffffffffffffffffffffffffffffffffffffffffffffff84169360f81c8015614f23575b61255c5784614e65575091614e27817fc0b7cf12926534c2d86d0abb17d620a3a06e07a84b3b8156a4b21189222b16d29361488d614ddd6001809998015473ffffffffffffffffffffffffffffffffffffffff9060501c1690565b9c7f01000000000000000000000000000000000000000000000000000000000000007effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff825416179055565b60408051998a523360208b015279ffffffffffffffffffffffffffffffffffffffffffffffffffff929092169189019190915296606090a101614cee565b98919392906124b06001614e9292015473ffffffffffffffffffffffffffffffffffffffff9060501c1690565b73ffffffffffffffffffffffffffffffffffffffff8a16036121c657614e278160019561488d7fc0b7cf12926534c2d86d0abb17d620a3a06e07a84b3b8156a4b21189222b16d2957f01000000000000000000000000000000000000000000000000000000000000007effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff825416179055565b508315614d82565b73ffffffffffffffffffffffffffffffffffffffff163303614f4957565b60046040517f48f5c3ed000000000000000000000000000000000000000000000000000000008152fd5b73ffffffffffffffffffffffffffffffffffffffff1660005260046020526001604060002054036121c657565b34811115614fd25760046040517f8ffff980000000000000000000000000000000000000000000000000000000008152fd5b803411614fdc5750565b611b50905a903403337f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26158e3565b64ffffffffff9061501b816145fc565b5460b01c16421061502857565b60046040517ff9ad93f5000000000000000000000000000000000000000000000000000000008152fd5b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167404000000000000000000000000000000000000000017905560408051918252600460208301527fc1191e7178b58ad510709587719f39ec315fa79e81ee7ba5c5ef3c894e94a65191a1565b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167406000000000000000000000000000000000000000017905560408051918252600660208301527fc1191e7178b58ad510709587719f39ec315fa79e81ee7ba5c5ef3c894e94a65191a1565b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167407000000000000000000000000000000000000000017905560408051918252600760208301527fc1191e7178b58ad510709587719f39ec315fa79e81ee7ba5c5ef3c894e94a65191a1565b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167405000000000000000000000000000000000000000017905560408051918252600560208301527fc1191e7178b58ad510709587719f39ec315fa79e81ee7ba5c5ef3c894e94a65191a1565b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167402000000000000000000000000000000000000000017905560408051918252600260208301527fc1191e7178b58ad510709587719f39ec315fa79e81ee7ba5c5ef3c894e94a65191a1565b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167403000000000000000000000000000000000000000017905560408051918252600360208301527fc1191e7178b58ad510709587719f39ec315fa79e81ee7ba5c5ef3c894e94a65191a1565b6040519291906005016153048461066e565b64ffffffffff809216845273ffffffffffffffffffffffffffffffffffffffff60208501931683528054680100000000000000008110156106315761534e916001820181556139db565b9390936153a85751835492517fffffffffffffff000000000000000000000000000000000000000000000000009390931691161760289190911b78ffffffffffffffffffffffffffffffffffffffff000000000016179055565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b8115613b89570690565b60019391848101808211612bde578015613b8957820694600886811c9260ff908380838b161b945b61542f575b505050506154299061542083876139c7565b511791856139c7565b52929190565b9380615443878b9c9599969c9894986139c7565b5116156154915750505081906040516154688161168260208201948560209181520190565b5190209361547e61547885613791565b866153d7565b9788811c9483838b161b94909193615409565b9382995083965081955061540e565b805191821561553a576000925b808410615509575082151591826154eb575b5050156135f1577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b6155009192506154fa84613899565b906139c7565b511438806154bf565b6155138185615a17565b90818361552082876139c7565b51111561552e5750506154ad565b600101945090506154ad565b505050600090565b907f000000000000000000000000271682deb8c4e0901d1a1550ad2e64d568e6990973ffffffffffffffffffffffffffffffffffffffff81163303615618575081600052600560205260406000205460ff811661559e57505050565b69ffffffffffffffffffff9060081c1680600052600260205260406000209060026155ce835460ff9060a01c1690565b6155d781611d4a565b146155e3575b50505050565b6001926155f66155fb9261560d94615282565b6139ba565b51926000526005602052604060002090565b0155388080806155dd565b6040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff919091166024820152604490fd5b73ffffffffffffffffffffffffffffffffffffffff60005416330361568857565b60046040517f30cd7471000000000000000000000000000000000000000000000000000000008152fd5b60ff60015460b01c166156c157565b60046040517f1309a563000000000000000000000000000000000000000000000000000000008152fd5b3d15615744573d9067ffffffffffffffff8211610631576040519161573860207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601846106a7565b82523d6000602084013e565b606090565b91909392823b1561426657600094859485926040519260208401957ff242432a00000000000000000000000000000000000000000000000000000000875273ffffffffffffffffffffffffffffffffffffffff80921660248601521660448401526064830152608482015260a060a48201528160c482015260c481526157ce8161068a565b51925af16157da6156eb565b50156157e257565b60046040517f02f8f11e000000000000000000000000000000000000000000000000000000008152fd5b908160209103126102d257516135f1816104e6565b909192813b15614266576040519260208401947f23b872dd00000000000000000000000000000000000000000000000000000000865273ffffffffffffffffffffffffffffffffffffffff809216602486015216604484015260648301526064825260a082019282841067ffffffffffffffff851117610631576000809493819460405251925af16158b16156eb565b50156158b957565b60046040517fe0f5c508000000000000000000000000000000000000000000000000000000008152fd5b6158f882849395600080809781948294f11590565b6159025750505050565b73ffffffffffffffffffffffffffffffffffffffff16803b15615a1357604051937fd0e30db0000000000000000000000000000000000000000000000000000000008552838560048186865af1938415610cdd576159bb95602095615a00575b506040518096819582947fa9059cbb000000000000000000000000000000000000000000000000000000008452600484016020909392919373ffffffffffffffffffffffffffffffffffffffff60408201951681520152565b03925af18015610cdd576159d2575b8080806155dd565b6159f29060203d81116159f9575b6159ea81836106a7565b81019061580c565b50386159ca565b503d6159e0565b80610cd1615a0d9261061d565b38615962565b8280fd5b90808216911860011c8101809111612bde579056fea2646970667358221220bf93bd80b91da28dc011ba8a77ed5bfbd550a6ba0168ccc0f3dc76a965b0552364736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28af398995b04c28e9951adb9721ef74c74f93e6a478f39e7e0777be13527e7ef00000000000000000000000000000000000000000000000000000000000002de000000000000000000000000271682deb8c4e0901d1a1550ad2e64d568e69909000000000000000000000000b5a9e5a319c7fda551a30be592c77394bf935c6f000000000000000000000000b5a9e5a319c7fda551a30be592c77394bf935c6f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ea4af05656c17b90f4d64add29e1d
-----Decoded View---------------
Arg [0] : _weth (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
Arg [1] : _keyHash (bytes32): 0x8af398995b04c28e9951adb9721ef74c74f93e6a478f39e7e0777be13527e7ef
Arg [2] : _subscriptionId (uint64): 734
Arg [3] : _vrfCoordinator (address): 0x271682DEB8C4E0901D1a1550aD2e64D568E69909
Arg [4] : _owner (address): 0xB5a9e5a319c7fDa551a30BE592c77394bF935c6f
Arg [5] : _protocolFeeRecipient (address): 0xB5a9e5a319c7fDa551a30BE592c77394bF935c6f
Arg [6] : _protocolFeeBp (uint16): 0
Arg [7] : _transferManager (address): 0x00000000000ea4af05656C17b90f4d64AdD29e1d
-----Encoded View---------------
8 Constructor Arguments found :
Arg [0] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [1] : 8af398995b04c28e9951adb9721ef74c74f93e6a478f39e7e0777be13527e7ef
Arg [2] : 00000000000000000000000000000000000000000000000000000000000002de
Arg [3] : 000000000000000000000000271682deb8c4e0901d1a1550ad2e64d568e69909
Arg [4] : 000000000000000000000000b5a9e5a319c7fda551a30be592c77394bf935c6f
Arg [5] : 000000000000000000000000b5a9e5a319c7fda551a30be592c77394bf935c6f
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [7] : 00000000000000000000000000000000000ea4af05656c17b90f4d64add29e1d
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.