Feature Tip: Add private address tag to any address under My Name Tag !
More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 216 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Deposit | 20085948 | 36 days ago | IN | 0.01 ETH | 0.00099985 | ||||
Cancel | 20074988 | 38 days ago | IN | 0 ETH | 0.00296061 | ||||
Deposit | 20074689 | 38 days ago | IN | 0.01 ETH | 0.00172857 | ||||
Cancel | 20032387 | 44 days ago | IN | 0 ETH | 0.00173394 | ||||
Deposit | 20032086 | 44 days ago | IN | 0 ETH | 0.00366788 | ||||
Cancel | 19964703 | 53 days ago | IN | 0 ETH | 0.00093662 | ||||
Deposit | 19964404 | 53 days ago | IN | 0.01 ETH | 0.00117005 | ||||
Cancel | 19940589 | 57 days ago | IN | 0 ETH | 0.00155465 | ||||
Deposit | 19940291 | 57 days ago | IN | 0.01 ETH | 0.0011059 | ||||
Withdraw Deposit... | 19924170 | 59 days ago | IN | 0 ETH | 0.00032637 | ||||
Cancel | 19917819 | 60 days ago | IN | 0 ETH | 0.00074492 | ||||
Deposit | 19917521 | 60 days ago | IN | 0.01 ETH | 0.00104635 | ||||
Withdraw Deposit... | 19917493 | 60 days ago | IN | 0 ETH | 0.00043266 | ||||
Cancel | 19912167 | 61 days ago | IN | 0 ETH | 0.00155541 | ||||
Deposit | 19911867 | 61 days ago | IN | 0.01 ETH | 0.00134715 | ||||
Withdraw Deposit... | 19906556 | 61 days ago | IN | 0 ETH | 0.00024251 | ||||
Cancel | 19904557 | 62 days ago | IN | 0 ETH | 0.00044902 | ||||
Cancel | 19904257 | 62 days ago | IN | 0 ETH | 0.00020126 | ||||
Cancel | 19903957 | 62 days ago | IN | 0 ETH | 0.00021727 | ||||
Deposit ETH Into... | 19903660 | 62 days ago | IN | 0.03 ETH | 0.00115375 | ||||
Cancel | 19859656 | 68 days ago | IN | 0 ETH | 0.00048785 | ||||
Cancel | 19859355 | 68 days ago | IN | 0 ETH | 0.00023508 | ||||
Deposit ETH Into... | 19859054 | 68 days ago | IN | 0.02 ETH | 0.00081652 | ||||
Cancel | 19834285 | 72 days ago | IN | 0 ETH | 0.00051167 | ||||
Deposit | 19833987 | 72 days ago | IN | 0 ETH | 0.00096612 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
19924170 | 59 days ago | 0.01 ETH | ||||
19917493 | 60 days ago | 0.01 ETH | ||||
19906556 | 61 days ago | 0.03 ETH | ||||
19769087 | 81 days ago | 0.05 ETH | ||||
19731721 | 86 days ago | 0.05 ETH | ||||
19677763 | 93 days ago | 0.021 ETH | ||||
19658007 | 96 days ago | 0.01 ETH | ||||
19610557 | 103 days ago | 0.01 ETH | ||||
19609428 | 103 days ago | 0.01 ETH | ||||
19598886 | 104 days ago | 0.01 ETH | ||||
19493413 | 119 days ago | 0.05 ETH | ||||
19457501 | 124 days ago | 0.02 ETH | ||||
19442336 | 127 days ago | 0.01 ETH | ||||
19399692 | 133 days ago | 0.1 ETH | ||||
19305530 | 146 days ago | 0.05 ETH | ||||
19275938 | 150 days ago | 0.02 ETH | ||||
19264937 | 151 days ago | 0.02 ETH | ||||
19246460 | 154 days ago | 0.02 ETH | ||||
19234880 | 156 days ago | 0.0285 ETH | ||||
19234880 | 156 days ago | 0.0015 ETH | ||||
19229829 | 156 days ago | 0.01 ETH | ||||
19225396 | 157 days ago | 0.01 ETH | ||||
19223353 | 157 days ago | 0.01 ETH | ||||
19222315 | 157 days ago | 0.01 ETH | ||||
19209520 | 159 days ago | 0.019 ETH |
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
YoloV2
Compiler Version
v0.8.23+commit.f704f362
Optimization Enabled:
Yes with 888888 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; import {ITransferManager} from "@looksrare/contracts-transfer-manager/contracts/interfaces/ITransferManager.sol"; import {TokenType as TransferManager__TokenType} from "@looksrare/contracts-transfer-manager/contracts/enums/TokenType.sol"; import {IERC20} from "@looksrare/contracts-libs/contracts/interfaces/generic/IERC20.sol"; import {SignatureCheckerMemory} from "@looksrare/contracts-libs/contracts/SignatureCheckerMemory.sol"; import {ReentrancyGuard} from "@looksrare/contracts-libs/contracts/ReentrancyGuard.sol"; import {Pausable} from "@looksrare/contracts-libs/contracts/Pausable.sol"; 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 {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol"; import {VRFCoordinatorV2Interface} from "@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol"; import {VRFConsumerBaseV2} from "@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol"; import {IYoloV2} from "./interfaces/IYoloV2.sol"; import {IPriceOracle} from "./interfaces/IPriceOracle.sol"; import {Arrays} from "./libraries/Arrays.sol"; import {AlreadyWithdrawn_error_selector, CutoffTimeNotReached_error_selector, DrawExpirationTimeNotReached_error_selector, InsufficientParticipants_error_selector, InvalidIndex_error_selector, InvalidLength_error_selector, InvalidSignatureTimestamp_error_selector, InvalidStatus_error_selector, InvalidToken_error_selector, InvalidTokenType_error_selector, InvalidValue_error_selector, LooksAlreadySet_error_selector, MaximumNumberOfDepositsReached_error_selector, MaximumNumberOfParticipantsReached_error_selector, MessageIdInvalid_error_selector, NotDepositor_error_selector, NotOperator_error_selector, NotOwner_error_selector, NotWinner_error_selector, OnePlayerCannotFillUpTheWholeRound_error_selector, OutflowNotAllowed_error_selector, ProtocolFeeNotPaid_error_selector, RandomnessRequestAlreadyExists_error_selector, RoundCannotBeClosed_error_selector, TooFewEntries_error_selector, ZeroDeposits_error_selector, ZeroEntries_error_selector, ZeroRounds_error_selector, Error_selector_offset, Error_standard_length} from "./constants/AssemblyConstants.sol"; // @@@@@@@@@@@@@ @@@@@@@@@@@@@ // @@@@@@@@@@@@@@@ @@@@@@@@@@@@@@ @@@@%*+++++++++*%@@@@ @@@@@@@@@@@@@@ @@@@%+-:::::::-+%@@@@ // @#:........=@@ @@*.........+@@@@*=================*@@@ @@=........=@@ @@@+.................+@@@ // @@=........:#@@ @@.........:@@%+=====================+%@@ @@=........=@@ @@%-.....................-#@@ // @@%:........=@@ @@=........:%@*=========================+%@@@=........=@@ @@%-.........................=@@@ // @@+........:#@ @@#........:%%============================+#@@=........=@@ @@#:...........................:#@@ // @@:........+@@ @@:.......:#%%@#*=======*%%@@@%%*==========+%@=........=@@ @#:.........:=*%%@%%#=..........:#@@ // @@#........:%@ @@+........+%+==+#@@*==#@@@@ @@@@#=========+@#........=@@ @%-........:*@@@@ @@@@+:........-%@ // @@=........=@@@#:.......-%*=======*@@@@ @@@=========*@:.......+@@ @@*.........@@@ @@%:........+@@ // @%:.......:%@@=........=@+========*@@ @%=========@+.......+@@ @@-........%@@ @@*........=%@ // @@+:.....:.-@#:.:......+@@@@@@@@@@@@ @@%%%%%%%%#@#::....:+@@ @@:.:.....:@@ @@::.:..:.-%@ // @%-::::::::*-:::::::::@@*+++++++*@@ @@+++++++++@*:::::::+@@ @@:::::::::%@ @@%::::::::-%@ // @@%********=:::::::::*@@*+*#%@@@##@@ @@*========+@=:::::::+@@ @@=::::::::=@@ @@=::::::::+@@ // @@@@@@@@@@:::::::::=@@@@@#*++++++*@@ @@@+=========%@::::::::+@@ @%:::::::::=@@@ @@@=:::::::::#@@ // @@=:::::::::%@ @@*++++++++++*@@@@@@@@@*+========+#@+::::::::+%@@@@@@@%+::::::::::+@@@@@@@@@+::::::::::+@@ // @@#:::::::::*@@ @@*+++++++++*@#++++++==========+*@@+::::::::::::::::::::::::::::::::-===-::::::::::::=@@ // @@-::::::::-%@ @@#++++++++%%+===============+#@@@+::::::::::::::::::::::::::::::::::::::::::::::::*@@ // @@+:::::::::*@@ @@@*+++++%%+===============*%@@@@+:::::::::::::::::::::*=:::::::::::::::::::::::=%@@ // @%-::::::::=@@ @@@#++#@*+============+*@@@ @@+:::::::::::::::::::::%@%+-::::::::::::::::::+%@@ // @@%*********%@@ @@@@@*+==========+#@@@@ @@#*********************%@@@@@*-:::::::::::-*@@@@ // @@@@@@@@@@@@@@ @@@@@@@%%%@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@%%%@@@@@@@ // @@@@ @@@@@ /** * @title YoloV2 * @notice This contract permissionlessly hosts yolos on LooksRare. * @author LooksRare protocol team (👀,💎) */ contract YoloV2 is IYoloV2, AccessControl, VRFConsumerBaseV2, LowLevelWETH, LowLevelERC20Transfer, LowLevelERC721Transfer, ReentrancyGuard, Pausable { using Arrays for uint256[]; /** * @notice Operators are allowed to add/remove allowed ERC-20 and ERC-721 tokens. */ bytes32 private constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE"); /** * @notice The TWAP period in seconds to use. */ uint256 private constant TWAP_DURATION = 3_600; /** * @notice The maximum protocol fee in basis points, which is 25%. */ uint16 private constant MAXIMUM_PROTOCOL_FEE_BP = 2_500; /** * @notice The maximum number of deposits per round. */ uint256 private constant MAXIMUM_NUMBER_OF_DEPOSITS_PER_ROUND = 100; /** * @notice Reservoir oracle's message typehash. * @dev It is used to compute the hash of the message using the (message) id, the payload, and the timestamp. */ bytes32 private constant RESERVOIR_ORACLE_MESSAGE_TYPEHASH = keccak256("Message(bytes32 id,bytes payload,uint256 timestamp,uint256 chainId)"); /** * @notice Reservoir oracle's ID typehash. * @dev It is used to compute the hash of the ID using price kind, TWAP seconds, and the contract address. */ bytes32 private constant RESERVOIR_ORACLE_ID_TYPEHASH = keccak256( "ContractWideCollectionPrice(uint8 kind,uint256 twapSeconds,address contract,bool onlyNonFlaggedTokens)" ); /** * @notice The bits offset of the round's maximum number of participants in a round slot. */ uint256 private constant ROUND__MAXIMUM_NUMBER_OF_PARTICIPANTS_OFFSET = 8; /** * @notice The bits offset of the round's protocol fee basis points in a round slot. */ uint256 private constant ROUND__PROTOCOL_FEE_BP_OFFSET = 48; /** * @notice The bits offset of the round's cutoff time in a round slot. */ uint256 private constant ROUND__CUTOFF_TIME_OFFSET = 64; /** * @notice The bits offset of the round's value per entry in a round slot. */ uint256 private constant ROUND__VALUE_PER_ENTRY_OFFSET = 160; /** * @notice The slot offset of the round's value per entry starting from the round's slot. */ uint256 private constant ROUND__VALUE_PER_ENTRY_SLOT_OFFSET = 1; /** * @notice The bits offset of the randomness request's round ID in a randomness request slot. */ uint256 private constant RANDOMNESS_REQUEST__ROUND_ID_OFFSET = 8; /** * @notice The slot offset of the round's deposits length starting from the round's slot. */ uint256 private constant ROUND__DEPOSITS_LENGTH_SLOT_OFFSET = 3; /** * @notice The number of slots a round struct occupies. */ uint256 private constant DEPOSIT__OCCUPIED_SLOTS = 4; /** * @notice The slot offset of the deposit's token ID starting from the deposit's slot. */ uint256 private constant DEPOSIT__TOKEN_ID_SLOT_OFFSET = 1; /** * @notice The slot offset of the deposit's token amount starting from the deposit's slot. */ uint256 private constant DEPOSIT__TOKEN_AMOUNT_SLOT_OFFSET = 2; /** * @notice The slot offset of the deposit's last slot starting from the deposit's slot. */ uint256 private constant DEPOSIT__LAST_SLOT_OFFSET = 3; /** * @notice The bits offset of the deposit's token address in the deposit's slot 0. */ uint256 private constant DEPOSIT__TOKEN_ADDRESS_OFFSET = 8; /** * @notice The bits offset of the deposit's current entry index in the deposit's slot 3. */ uint256 private constant DEPOSIT__CURRENT_ENTRY_INDEX_OFFSET = 168; /** * @notice Wrapped Ether address. */ address private immutable WETH; /** * @notice The key hash of the Chainlink VRF. */ bytes32 private immutable KEY_HASH; /** * @notice The subscription ID of the Chainlink VRF. */ uint64 private immutable SUBSCRIPTION_ID; /** * @notice The Chainlink VRF coordinator. */ VRFCoordinatorV2Interface private immutable VRF_COORDINATOR; /** * @notice The minimum number of confirmation blocks on VRF requests before oracles respond. */ uint16 private immutable MINIMUM_REQUEST_CONFIRMATIONS; /** * @notice Transfer manager faciliates token transfers. */ ITransferManager private immutable transferManager; /** * @notice LOOKS token address. */ address private LOOKS; /** * @notice The value of each entry in ETH. */ uint96 public valuePerEntry; /** * @notice The duration of each round. */ uint40 public roundDuration; /** * @notice The protocol fee basis points. */ uint16 public protocolFeeBp; /** * @notice The discounted protocol fee basis points if paid with LOOKS. */ uint16 public discountedProtocolFeeBp; /** * @notice Number of rounds that have been created. * @dev In this smart contract, roundId is an uint256 but its * max value can only be 2^40 - 1. Realistically we will still * not reach this number. */ uint40 public roundsCount; /** * @notice The maximum number of participants per round. */ uint40 public maximumNumberOfParticipantsPerRound; /** * @notice Whether token outflow is allowed. */ bool public outflowAllowed = true; /** * @notice The address of the protocol fee recipient. */ address private protocolFeeRecipient; /** * @notice ERC-20 oracle address. */ IPriceOracle public erc20Oracle; /** * @notice Reservoir oracle address. */ address public reservoirOracle; /** * @notice Reservoir oracle's signature validity period. */ uint40 public signatureValidityPeriod; /** * @notice It checks whether the token is allowed. * @dev 0 is not allowed, 1 is allowed. * token is the hash of the token address and the token type. */ mapping(bytes32 token => uint256 isAllowed) private isTokenAllowed; mapping(uint256 roundId => Round) private rounds; /** * @notice The deposit count of a user in any given round. */ mapping(uint256 roundId => mapping(address depositor => uint256 depositCount)) public depositCount; /** * @notice Chainlink randomness requests. */ mapping(uint256 requestId => RandomnessRequest) public randomnessRequests; /** * @notice The price of an ERC-20/ERC-712 token or a collection in any given round. */ mapping(address tokenOrCollection => mapping(uint256 roundId => uint256 price)) public prices; /** * @param params The constructor params. */ constructor(ConstructorCalldata memory params) VRFConsumerBaseV2(params.vrfCoordinator) { _grantRole(DEFAULT_ADMIN_ROLE, params.owner); _grantRole(OPERATOR_ROLE, params.operator); _updateRoundDuration(params.roundDuration); _updateProtocolFeeRecipient(params.protocolFeeRecipient); _updateProtocolFeeBp(params.protocolFeeBp); _updateDiscountedProtocolFeeBp(params.discountedProtocolFeeBp); _updateValuePerEntry(params.valuePerEntry); _updateERC20Oracle(params.erc20Oracle); _updateMaximumNumberOfParticipantsPerRound(params.maximumNumberOfParticipantsPerRound); _updateReservoirOracle(params.reservoirOracle); _updateSignatureValidityPeriod(params.signatureValidityPeriod); WETH = params.weth; KEY_HASH = params.keyHash; VRF_COORDINATOR = VRFCoordinatorV2Interface(params.vrfCoordinator); SUBSCRIPTION_ID = params.subscriptionId; MINIMUM_REQUEST_CONFIRMATIONS = params.minimumRequestConfirmations; transferManager = ITransferManager(params.transferManager); _startRound({_roundsCount: 0}); } /** * @param looks The LOOKS token address. */ function setLOOKS(address looks) external { _validateIsOwner(); if (LOOKS != address(0)) { _revertWith(LooksAlreadySet_error_selector); } LOOKS = looks; } /** * @inheritdoc IYoloV2 */ function deposit(uint256 roundId, DepositCalldata[] calldata deposits) external payable nonReentrant whenNotPaused { _deposit(roundId, deposits); } /** * @inheritdoc IYoloV2 */ function depositETHIntoMultipleRounds( uint256 startingRoundId, uint256[] calldata amounts ) external payable nonReentrant whenNotPaused { uint256 numberOfRounds = amounts.length; if (numberOfRounds == 0) { _revertWith(ZeroDeposits_error_selector); } Round storage startingRound = rounds[startingRoundId]; _validateRoundIsOpen(startingRound); _setCutoffTimeIfNotSet(startingRound); uint256 expectedValue; uint256[] memory entriesCounts = new uint256[](numberOfRounds); for (uint256 i; i < numberOfRounds; ++i) { uint256 roundId = _unsafeAdd(startingRoundId, i); Round storage round = rounds[roundId]; uint256 roundValuePerEntry = round.valuePerEntry; if (roundValuePerEntry == 0) { roundValuePerEntry = _writeDataToRound({roundId: roundId, roundValue: 0}); } _incrementUserDepositCount(roundId, round); uint256 depositAmount = amounts[i]; if (depositAmount % roundValuePerEntry != 0) { _revertWithInvalidValue(); } uint256 entriesCount = _depositETH(round, roundId, roundValuePerEntry, depositAmount); expectedValue += depositAmount; entriesCounts[i] = entriesCount; } if (expectedValue != msg.value) { _revertWithInvalidValue(); } emit MultipleRoundsDeposited(msg.sender, startingRoundId, amounts, entriesCounts); if ( _shouldDrawWinner( startingRound.numberOfParticipants, startingRound.maximumNumberOfParticipants, startingRound.deposits.length ) ) { _drawWinner(startingRound, startingRoundId); } } /** * @inheritdoc IYoloV2 */ function getRound( uint256 roundId ) external view returns ( RoundStatus status, uint40 maximumNumberOfParticipants, uint16 roundProtocolFeeBp, uint40 cutoffTime, uint40 drawnAt, uint40 numberOfParticipants, address winner, uint96 roundValuePerEntry, uint256 protocolFeeOwed, Deposit[] memory deposits ) { status = rounds[roundId].status; maximumNumberOfParticipants = rounds[roundId].maximumNumberOfParticipants; roundProtocolFeeBp = rounds[roundId].protocolFeeBp; cutoffTime = rounds[roundId].cutoffTime; drawnAt = rounds[roundId].drawnAt; numberOfParticipants = rounds[roundId].numberOfParticipants; winner = rounds[roundId].winner; roundValuePerEntry = rounds[roundId].valuePerEntry; protocolFeeOwed = rounds[roundId].protocolFeeOwed; deposits = rounds[roundId].deposits; } /** * @inheritdoc IYoloV2 */ function drawWinner() external nonReentrant whenNotPaused { uint256 roundId = roundsCount; Round storage round = rounds[roundId]; _validateRoundStatus(round, RoundStatus.Open); uint256 numberOfParticipants = round.numberOfParticipants; if (!_shouldDrawWinner(numberOfParticipants, round.maximumNumberOfParticipants, round.deposits.length)) { if (block.timestamp < round.cutoffTime) { _revertWith(CutoffTimeNotReached_error_selector); } if (numberOfParticipants < 2) { _revertWith(InsufficientParticipants_error_selector); } } _drawWinner(round, roundId); } /** * @inheritdoc IYoloV2 */ function cancel() external nonReentrant { _validateOutflowIsAllowed(); _cancel({roundId: roundsCount}); } /** * @inheritdoc IYoloV2 */ function cancel(uint256 numberOfRounds) external { _validateIsOwner(); if (numberOfRounds == 0) { _revertWith(ZeroRounds_error_selector); } _cancelMultipleRounds(numberOfRounds); } /** * @inheritdoc IYoloV2 */ function cancelAfterRandomnessRequest() external nonReentrant { _validateOutflowIsAllowed(); uint256 roundId = roundsCount; Round storage round = rounds[roundId]; _validateRoundStatus(round, RoundStatus.Drawing); if (block.timestamp < round.drawnAt + 25 hours) { _revertWith(DrawExpirationTimeNotReached_error_selector); } _setRoundStatus(round, roundId, RoundStatus.Cancelled); _startRound({_roundsCount: roundId}); } /** * @inheritdoc IYoloV2 */ function claimPrizes( WithdrawalCalldata[] calldata withdrawalCalldata, bool payWithLOOKS ) external payable nonReentrant { _validateOutflowIsAllowed(); TransferAccumulator memory transferAccumulator; uint256 ethAmount; uint256 protocolFeeOwed; _validateArrayLengthIsNotEmpty(withdrawalCalldata.length); if (payWithLOOKS) { if (msg.value != 0) { _revertWithInvalidValue(); } } for (uint256 i; i < withdrawalCalldata.length; ++i) { WithdrawalCalldata calldata perRoundWithdrawalCalldata = withdrawalCalldata[i]; Round storage round = rounds[perRoundWithdrawalCalldata.roundId]; _validateRoundStatus(round, RoundStatus.Drawn); _validateMsgSenderIsWinner(round); uint256[] calldata depositIndices = perRoundWithdrawalCalldata.depositIndices; _validateArrayLengthIsNotEmpty(depositIndices.length); for (uint256 j; j < depositIndices.length; ++j) { uint256 index = depositIndices[j]; _validateDepositsArrayIndex(index, round.deposits.length); ethAmount = _transferTokenOut(round.deposits[index], transferAccumulator, ethAmount); } protocolFeeOwed += round.protocolFeeOwed; round.protocolFeeOwed = 0; } if (protocolFeeOwed != 0) { if (payWithLOOKS) { _payForProtocolFeesInLOOKS(protocolFeeOwed); } else { _payForProtocolFeesInETH(protocolFeeOwed); protocolFeeOwed -= msg.value; if (protocolFeeOwed <= ethAmount) { unchecked { ethAmount -= protocolFeeOwed; } } else { _revertWith(ProtocolFeeNotPaid_error_selector); } } } if (transferAccumulator.amount != 0) { _executeERC20DirectTransfer(transferAccumulator.tokenAddress, msg.sender, transferAccumulator.amount); } if (ethAmount != 0) { _transferETHAndWrapIfFailWithGasLimit(WETH, msg.sender, ethAmount, gasleft()); } emit PrizesClaimed(msg.sender, withdrawalCalldata); } /** * @inheritdoc IYoloV2 * @dev This function does not validate withdrawalCalldata to not contain duplicate round IDs and prize indices. * It is the responsibility of the caller to ensure that. Otherwise, the returned protocol fee owed will be incorrect. */ function getClaimPrizesPaymentRequired( WithdrawalCalldata[] calldata withdrawalCalldata, bool payWithLOOKS ) external view returns (uint256 protocolFeeOwed) { uint256 ethAmount; for (uint256 i; i < withdrawalCalldata.length; ++i) { WithdrawalCalldata calldata perRoundWithdrawalCalldata = withdrawalCalldata[i]; Round storage round = rounds[perRoundWithdrawalCalldata.roundId]; _validateRoundStatus(round, RoundStatus.Drawn); uint256[] calldata depositIndices = perRoundWithdrawalCalldata.depositIndices; uint256 numberOfPrizes = depositIndices.length; uint256 prizesCount = round.deposits.length; for (uint256 j; j < numberOfPrizes; ++j) { uint256 index = depositIndices[j]; if (index >= prizesCount) { _revertWith(InvalidIndex_error_selector); } Deposit storage prize = round.deposits[index]; if (prize.tokenType == YoloV2__TokenType.ETH) { ethAmount += prize.tokenAmount; } } protocolFeeOwed += round.protocolFeeOwed; } if (payWithLOOKS) { protocolFeeOwed = _protocolFeeOwedInLOOKS(protocolFeeOwed); } else { if (protocolFeeOwed < ethAmount) { protocolFeeOwed = 0; } else { unchecked { protocolFeeOwed -= ethAmount; } } } } /** * @inheritdoc IYoloV2 */ function estimatedERC20DepositEntriesCount( uint256 roundId, DepositCalldata calldata singleDeposit ) external view returns (uint256 entriesCount) { address tokenAddress = singleDeposit.tokenAddress; uint256 price = prices[tokenAddress][roundId]; if (price == 0) { price = _getTWAP(tokenAddress); } entriesCount = ((price * singleDeposit.tokenIdsOrAmounts[0]) / (10 ** IERC20(tokenAddress).decimals())) / rounds[roundId].valuePerEntry; } /** * @inheritdoc IYoloV2 */ function withdrawDeposits(WithdrawalCalldata[] calldata withdrawalCalldata) external nonReentrant { _validateOutflowIsAllowed(); TransferAccumulator memory transferAccumulator; uint256 ethAmount; _validateArrayLengthIsNotEmpty(withdrawalCalldata.length); for (uint256 i; i < withdrawalCalldata.length; ++i) { WithdrawalCalldata calldata perRoundWithdrawalCalldata = withdrawalCalldata[i]; Round storage round = rounds[perRoundWithdrawalCalldata.roundId]; _validateRoundStatus(round, RoundStatus.Cancelled); uint256[] calldata depositIndices = perRoundWithdrawalCalldata.depositIndices; uint256 depositIndicesLength = depositIndices.length; _validateArrayLengthIsNotEmpty(depositIndicesLength); for (uint256 j; j < depositIndicesLength; ++j) { uint256 index = depositIndices[j]; _validateDepositsArrayIndex(index, round.deposits.length); Deposit storage singleDeposit = round.deposits[index]; _validateMsgSenderIsDepositor(singleDeposit); ethAmount = _transferTokenOut(singleDeposit, transferAccumulator, ethAmount); } } if (transferAccumulator.amount != 0) { _executeERC20DirectTransfer(transferAccumulator.tokenAddress, msg.sender, transferAccumulator.amount); } if (ethAmount != 0) { _transferETHAndWrapIfFailWithGasLimit(WETH, msg.sender, ethAmount, gasleft()); } emit DepositsWithdrawn(msg.sender, withdrawalCalldata); } /** * @inheritdoc IYoloV2 */ function rolloverETH( uint256 roundId, WithdrawalCalldata[] calldata withdrawalCalldata, bool payWithLOOKS ) external nonReentrant whenNotPaused { uint256 rolloverAmount; uint256 protocolFeeOwed; uint256 withdrawalCalldataLength = withdrawalCalldata.length; _validateArrayLengthIsNotEmpty(withdrawalCalldataLength); for (uint256 i; i < withdrawalCalldataLength; ++i) { WithdrawalCalldata calldata perRoundWithdrawalCalldata = withdrawalCalldata[i]; Round storage cancelledOrDrawnRound = rounds[perRoundWithdrawalCalldata.roundId]; RoundStatus status = cancelledOrDrawnRound.status; if (status < RoundStatus.Drawn) { _revertWithInvalidStatus(); } if (status == RoundStatus.Drawn) { _validateMsgSenderIsWinner(cancelledOrDrawnRound); protocolFeeOwed += cancelledOrDrawnRound.protocolFeeOwed; cancelledOrDrawnRound.protocolFeeOwed = 0; } uint256[] calldata depositIndices = perRoundWithdrawalCalldata.depositIndices; uint256 depositIndicesLength = depositIndices.length; _validateArrayLengthIsNotEmpty(depositIndicesLength); for (uint256 j; j < depositIndicesLength; ++j) { uint256 index = depositIndices[j]; _validateDepositsArrayIndex(index, cancelledOrDrawnRound.deposits.length); Deposit storage singleDeposit = cancelledOrDrawnRound.deposits[index]; _validateDepositNotWithdrawn(singleDeposit); if (singleDeposit.tokenType != YoloV2__TokenType.ETH) { _revertWith(InvalidTokenType_error_selector); } if (status == RoundStatus.Cancelled) { _validateMsgSenderIsDepositor(singleDeposit); } singleDeposit.withdrawn = true; rolloverAmount += singleDeposit.tokenAmount; } } if (protocolFeeOwed != 0) { if (payWithLOOKS) { _payForProtocolFeesInLOOKS(protocolFeeOwed); } else { if (rolloverAmount < protocolFeeOwed) { _revertWith(ProtocolFeeNotPaid_error_selector); } else { unchecked { rolloverAmount -= protocolFeeOwed; } } _payForProtocolFeesInETH(protocolFeeOwed); } } Round storage round = rounds[roundId]; _validateRoundIsOpen(round); _incrementUserDepositCount(roundId, round); _setCutoffTimeIfNotSet(round); uint256 roundValuePerEntry = round.valuePerEntry; uint256 dust = rolloverAmount % roundValuePerEntry; if (dust != 0) { _validateOutflowIsAllowed(); unchecked { rolloverAmount -= dust; } _transferETHAndWrapIfFailWithGasLimit(WETH, msg.sender, dust, gasleft()); } if (rolloverAmount < roundValuePerEntry) { _revertWithInvalidValue(); } uint256 entriesCount = _depositETH(round, roundId, roundValuePerEntry, rolloverAmount); if (_shouldDrawWinner(round.numberOfParticipants, round.maximumNumberOfParticipants, round.deposits.length)) { _drawWinner(round, roundId); } emit Rollover(msg.sender, withdrawalCalldata, roundId, entriesCount); } /** * @inheritdoc IYoloV2 */ function togglePaused() external { _validateIsOwner(); if (paused()) { _unpause(); _cancelMultipleRounds({numberOfRounds: 1}); } else { _pause(); } } /** * @inheritdoc IYoloV2 */ function toggleOutflowAllowed() external { _validateIsOwner(); bool _outflowAllowed = outflowAllowed; outflowAllowed = !_outflowAllowed; emit OutflowAllowedUpdated(!_outflowAllowed); } /** * @inheritdoc IYoloV2 */ function updateTokensStatus(address[] calldata tokens, YoloV2__TokenType tokenType, bool isAllowed) external { _validateIsOperator(); if (tokenType == YoloV2__TokenType.ETH) { _revertWithInvalidToken(); } uint256 count = tokens.length; for (uint256 i; i < count; ++i) { isTokenAllowed[keccak256(abi.encodePacked(tokens[i], tokenType))] = (isAllowed ? 1 : 0); } emit TokensStatusUpdated(tokens, tokenType, isAllowed); } /** * @inheritdoc IYoloV2 */ function updateRoundDuration(uint40 _roundDuration) external { _validateIsOwner(); _updateRoundDuration(_roundDuration); } /** * @inheritdoc IYoloV2 */ function updateSignatureValidityPeriod(uint40 _signatureValidityPeriod) external { _validateIsOwner(); _updateSignatureValidityPeriod(_signatureValidityPeriod); } /** * @inheritdoc IYoloV2 */ function updateValuePerEntry(uint96 _valuePerEntry) external { _validateIsOwner(); _updateValuePerEntry(_valuePerEntry); } /** * @inheritdoc IYoloV2 */ function updateProtocolFeeRecipient(address _protocolFeeRecipient) external { _validateIsOwner(); _updateProtocolFeeRecipient(_protocolFeeRecipient); } /** * @inheritdoc IYoloV2 */ function updateProtocolFeeBp(uint16 _protocolFeeBp) external { _validateIsOwner(); _updateProtocolFeeBp(_protocolFeeBp); } /** * @inheritdoc IYoloV2 */ function updateDiscountedProtocolFeeBp(uint16 _discountedProtocolFeeBp) external { _validateIsOwner(); _updateDiscountedProtocolFeeBp(_discountedProtocolFeeBp); } /** * @inheritdoc IYoloV2 */ function updateMaximumNumberOfParticipantsPerRound(uint40 _maximumNumberOfParticipantsPerRound) external { _validateIsOwner(); _updateMaximumNumberOfParticipantsPerRound(_maximumNumberOfParticipantsPerRound); } /** * @inheritdoc IYoloV2 */ function updateReservoirOracle(address _reservoirOracle) external { _validateIsOwner(); _updateReservoirOracle(_reservoirOracle); } /** * @inheritdoc IYoloV2 */ function updateERC20Oracle(address _erc20Oracle) external { _validateIsOwner(); _updateERC20Oracle(_erc20Oracle); } /** * @param round The round to update. * @param roundId The round's ID. * @param status The round's status. */ function _setRoundStatus(Round storage round, uint256 roundId, RoundStatus status) private { round.status = status; emit RoundStatusUpdated(roundId, status); } /** * @param _roundDuration The duration of each round. */ function _updateRoundDuration(uint40 _roundDuration) private { if (_roundDuration > 1 hours) { _revertWithInvalidValue(); } roundDuration = _roundDuration; emit RoundDurationUpdated(_roundDuration); } /** * @param _signatureValidityPeriod The validity period of a Reservoir signature. */ function _updateSignatureValidityPeriod(uint40 _signatureValidityPeriod) private { signatureValidityPeriod = _signatureValidityPeriod; emit SignatureValidityPeriodUpdated(_signatureValidityPeriod); } /** * @param _valuePerEntry The value of each entry in ETH. */ function _updateValuePerEntry(uint96 _valuePerEntry) private { if (_valuePerEntry == 0) { _revertWithInvalidValue(); } valuePerEntry = _valuePerEntry; emit ValuePerEntryUpdated(_valuePerEntry); } /** * @param _protocolFeeRecipient The new protocol fee recipient address */ function _updateProtocolFeeRecipient(address _protocolFeeRecipient) private { if (_protocolFeeRecipient == address(0)) { _revertWithInvalidValue(); } protocolFeeRecipient = _protocolFeeRecipient; emit ProtocolFeeRecipientUpdated(_protocolFeeRecipient); } /** * @param _protocolFeeBp The new protocol fee in basis points */ function _updateProtocolFeeBp(uint16 _protocolFeeBp) private { if (_protocolFeeBp > MAXIMUM_PROTOCOL_FEE_BP) { _revertWithInvalidValue(); } protocolFeeBp = _protocolFeeBp; emit ProtocolFeeBpUpdated(_protocolFeeBp); } /** * @param _discountedProtocolFeeBp The new discounted protocol fee in basis points */ function _updateDiscountedProtocolFeeBp(uint16 _discountedProtocolFeeBp) private { if (_discountedProtocolFeeBp > 10_000) { _revertWithInvalidValue(); } discountedProtocolFeeBp = _discountedProtocolFeeBp; emit DiscountedProtocolFeeBpUpdated(_discountedProtocolFeeBp); } /** * @param _maximumNumberOfParticipantsPerRound The new maximum number of participants per round */ function _updateMaximumNumberOfParticipantsPerRound(uint40 _maximumNumberOfParticipantsPerRound) private { if (_maximumNumberOfParticipantsPerRound < 2) { _revertWithInvalidValue(); } maximumNumberOfParticipantsPerRound = _maximumNumberOfParticipantsPerRound; emit MaximumNumberOfParticipantsPerRoundUpdated(_maximumNumberOfParticipantsPerRound); } /** * @param _reservoirOracle The new Reservoir oracle address */ function _updateReservoirOracle(address _reservoirOracle) private { if (_reservoirOracle == address(0)) { _revertWithInvalidValue(); } reservoirOracle = _reservoirOracle; emit ReservoirOracleUpdated(_reservoirOracle); } /** * @param _erc20Oracle The new ERC-20 oracle address */ function _updateERC20Oracle(address _erc20Oracle) private { if (_erc20Oracle == address(0)) { _revertWithInvalidValue(); } erc20Oracle = IPriceOracle(_erc20Oracle); emit ERC20OracleUpdated(_erc20Oracle); } /** * @param _roundsCount The current rounds count * @return roundId The started round ID */ function _startRound(uint256 _roundsCount) private returns (uint256 roundId) { unchecked { roundId = _roundsCount + 1; } roundsCount = uint40(roundId); Round storage round = rounds[roundId]; if (round.valuePerEntry == 0) { // On top of the 4 values covered by _writeDataToRound, this also writes the round's status to Open (1). _writeDataToRound({roundId: roundId, roundValue: 1}); } else { uint256 numberOfParticipants = round.numberOfParticipants; uint40 _roundDuration = roundDuration; // This is equivalent to // round.status = RoundStatus.Open; // if (round.numberOfParticipants > 0) { // round.cutoffTime = uint40(block.timestamp) + _roundDuration; // } uint256 roundSlot = _getRoundSlot(roundId); assembly { // RoundStatus.Open is equal to 1. let roundValue := or(sload(roundSlot), 1) if gt(numberOfParticipants, 0) { roundValue := or(roundValue, shl(ROUND__CUTOFF_TIME_OFFSET, add(timestamp(), _roundDuration))) } sstore(roundSlot, roundValue) } } emit RoundStatusUpdated(roundId, RoundStatus.Open); } /** * @param round The open round. * @param roundId The open round ID. */ function _drawWinner(Round storage round, uint256 roundId) private { _setRoundStatus(round, roundId, RoundStatus.Drawing); round.drawnAt = uint40(block.timestamp); uint256 requestId = VRF_COORDINATOR.requestRandomWords({ keyHash: KEY_HASH, subId: SUBSCRIPTION_ID, minimumRequestConfirmations: MINIMUM_REQUEST_CONFIRMATIONS, callbackGasLimit: uint32(500_000), numWords: uint32(1) }); if (randomnessRequests[requestId].exists) { _revertWith(RandomnessRequestAlreadyExists_error_selector); } // This is equivalent to // randomnessRequests[requestId].exists = true; // randomnessRequests[requestId].roundId = uint40(roundId); assembly { mstore(0x00, requestId) mstore(0x20, randomnessRequests.slot) let randomnessRequestSlot := keccak256(0x00, 0x40) // 1 is true sstore(randomnessRequestSlot, or(1, shl(RANDOMNESS_REQUEST__ROUND_ID_OFFSET, roundId))) } emit RandomnessRequested(roundId, requestId); } /** * @param roundId The open round ID. * @param deposits The ERC-20/ERC-721 deposits to be made. */ function _deposit(uint256 roundId, DepositCalldata[] calldata deposits) private { Round storage round = rounds[roundId]; _validateRoundIsOpen(round); _incrementUserDepositCount(roundId, round); _setCutoffTimeIfNotSet(round); uint256 roundDepositCount = round.deposits.length; uint40 currentEntryIndex; uint256 totalEntriesCount; uint256 roundDepositsLengthSlot = _getRoundSlot(roundId) + ROUND__DEPOSITS_LENGTH_SLOT_OFFSET; if (msg.value == 0) { if (deposits.length == 0) { _revertWith(ZeroDeposits_error_selector); } } else { uint256 roundValuePerEntry = round.valuePerEntry; if (msg.value % roundValuePerEntry != 0) { _revertWithInvalidValue(); } uint256 entriesCount = msg.value / roundValuePerEntry; totalEntriesCount += entriesCount; currentEntryIndex = _getCurrentEntryIndexWithoutAccrual(round, roundDepositCount, entriesCount); // This is equivalent to // round.deposits.push( // Deposit({ // tokenType: YoloV2__TokenType.ETH, // tokenAddress: address(0), // tokenId: 0, // tokenAmount: msg.value, // depositor: msg.sender, // withdrawn: false, // currentEntryIndex: currentEntryIndex // }) // ); uint256 depositDataSlotWithCountOffset = _getDepositDataSlotWithCountOffset( roundDepositsLengthSlot, roundDepositCount ); // We don't have to write tokenType, tokenAddress, tokenId, and withdrawn because they are 0. _writeDepositorAndCurrentEntryIndexToDeposit(depositDataSlotWithCountOffset, currentEntryIndex); _writeDepositAmountToDeposit(depositDataSlotWithCountOffset, msg.value); unchecked { ++roundDepositCount; } } if (deposits.length != 0) { ITransferManager.BatchTransferItem[] memory batchTransferItems = new ITransferManager.BatchTransferItem[]( deposits.length ); for (uint256 i; i < deposits.length; ++i) { DepositCalldata calldata singleDeposit = deposits[i]; address tokenAddress = singleDeposit.tokenAddress; if (isTokenAllowed[keccak256(abi.encodePacked(tokenAddress, singleDeposit.tokenType))] != 1) { _revertWithInvalidToken(); } uint256 price = prices[tokenAddress][roundId]; if (singleDeposit.tokenType == YoloV2__TokenType.ERC721) { if (price == 0) { price = _getReservoirPrice(singleDeposit); prices[tokenAddress][roundId] = price; } uint256 entriesCount = price / round.valuePerEntry; _validateNonZeroEntries(entriesCount); uint256[] memory amounts = new uint256[](singleDeposit.tokenIdsOrAmounts.length); for (uint256 j; j < singleDeposit.tokenIdsOrAmounts.length; ++j) { totalEntriesCount += entriesCount; currentEntryIndex = _incrementCurrentEntryIndex( currentEntryIndex, entriesCount, round, roundDepositCount ); uint256 tokenId = singleDeposit.tokenIdsOrAmounts[j]; // tokenAmount is in reality 1, but we never use it and it is cheaper to set it as 0. // This is equivalent to // round.deposits.push( // Deposit({ // tokenType: YoloV2__TokenType.ERC721, // tokenAddress: tokenAddress, // tokenId: tokenId, // tokenAmount: 0, // depositor: msg.sender, // withdrawn: false, // currentEntryIndex: currentEntryIndex // }) // ); // unchecked { // roundDepositCount += 1; // } uint256 depositDataSlotWithCountOffset = _getDepositDataSlotWithCountOffset( roundDepositsLengthSlot, roundDepositCount ); _writeDepositorAndCurrentEntryIndexToDeposit(depositDataSlotWithCountOffset, currentEntryIndex); _writeTokenAddressToDeposit( depositDataSlotWithCountOffset, YoloV2__TokenType.ERC721, tokenAddress ); assembly { sstore(add(depositDataSlotWithCountOffset, DEPOSIT__TOKEN_ID_SLOT_OFFSET), tokenId) roundDepositCount := add(roundDepositCount, 1) } amounts[j] = 1; } batchTransferItems[i].tokenAddress = tokenAddress; batchTransferItems[i].tokenType = TransferManager__TokenType.ERC721; batchTransferItems[i].itemIds = singleDeposit.tokenIdsOrAmounts; batchTransferItems[i].amounts = amounts; } else if (singleDeposit.tokenType == YoloV2__TokenType.ERC20) { if (price == 0) { price = _getTWAP(tokenAddress); prices[tokenAddress][roundId] = price; } uint256[] memory amounts = singleDeposit.tokenIdsOrAmounts; if (amounts.length != 1) { _revertWith(InvalidLength_error_selector); } uint256 amount = amounts[0]; uint256 entriesCount = ((price * amount) / (10 ** IERC20(tokenAddress).decimals())) / round.valuePerEntry; _validateNonZeroEntries(entriesCount); if (entriesCount < singleDeposit.minimumEntries) { _revertWith(TooFewEntries_error_selector); } batchTransferItems[i].tokenAddress = tokenAddress; batchTransferItems[i].tokenType = TransferManager__TokenType.ERC20; batchTransferItems[i].amounts = singleDeposit.tokenIdsOrAmounts; totalEntriesCount += entriesCount; currentEntryIndex = _incrementCurrentEntryIndex( currentEntryIndex, entriesCount, round, roundDepositCount ); // round.deposits.push( // Deposit({ // tokenType: YoloV2__TokenType.ERC20, // tokenAddress: tokenAddress, // tokenId: 0, // tokenAmount: amount, // depositor: msg.sender, // withdrawn: false, // currentEntryIndex: currentEntryIndex // }) // ); uint256 depositDataSlotWithCountOffset = _getDepositDataSlotWithCountOffset( roundDepositsLengthSlot, roundDepositCount ); _writeDepositorAndCurrentEntryIndexToDeposit(depositDataSlotWithCountOffset, currentEntryIndex); _writeDepositAmountToDeposit(depositDataSlotWithCountOffset, amount); _writeTokenAddressToDeposit(depositDataSlotWithCountOffset, YoloV2__TokenType.ERC20, tokenAddress); unchecked { ++roundDepositCount; } } } transferManager.transferBatchItemsAcrossCollections(batchTransferItems, msg.sender, address(this)); } assembly { sstore(roundDepositsLengthSlot, roundDepositCount) } { uint256 numberOfParticipants = round.numberOfParticipants; _validateRoundDepositsAndPlayers(roundDepositCount, numberOfParticipants); if (_shouldDrawWinner(numberOfParticipants, round.maximumNumberOfParticipants, roundDepositCount)) { _drawWinner(round, roundId); } } emit Deposited(msg.sender, roundId, totalEntriesCount); } /** * @param roundId The ID of the round to be cancelled. */ function _cancel(uint256 roundId) private { Round storage round = rounds[roundId]; _validateRoundStatus(round, RoundStatus.Open); uint256 cutoffTime = round.cutoffTime; if (cutoffTime == 0 || block.timestamp < cutoffTime) { _revertWith(CutoffTimeNotReached_error_selector); } if (round.numberOfParticipants > 1) { _revertWith(RoundCannotBeClosed_error_selector); } _setRoundStatus(round, roundId, RoundStatus.Cancelled); _startRound({_roundsCount: roundId}); } /** * @param numberOfRounds Number of rounds to cancel. */ function _cancelMultipleRounds(uint256 numberOfRounds) private { uint256 startingRoundId = roundsCount; for (uint256 i; i < numberOfRounds; ++i) { rounds[_unsafeAdd(startingRoundId, i)].status = RoundStatus.Cancelled; } emit RoundsCancelled(startingRoundId, numberOfRounds); _startRound({_roundsCount: _unsafeSubtract(_unsafeAdd(startingRoundId, numberOfRounds), 1)}); } /** * @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 roundId = randomnessRequests[requestId].roundId; Round storage round = rounds[roundId]; if (round.status == RoundStatus.Drawing) { _setRoundStatus(round, roundId, RoundStatus.Drawn); uint256 randomWord = randomWords[0]; randomnessRequests[requestId].randomWord = randomWord; uint256 count = round.deposits.length; uint256[] memory currentEntryIndexArray = new uint256[](count); for (uint256 i; i < count; ++i) { currentEntryIndexArray[i] = uint256(round.deposits[i].currentEntryIndex); } uint256 currentEntryIndex = currentEntryIndexArray[_unsafeSubtract(count, 1)]; uint256 winningEntry = _unsafeAdd(randomWord % currentEntryIndex, 1); round.winner = round.deposits[currentEntryIndexArray.findUpperBound(winningEntry)].depositor; round.protocolFeeOwed = (round.valuePerEntry * currentEntryIndex * round.protocolFeeBp) / 10_000; _startRound({_roundsCount: roundId}); } } } /** * @param roundId The round ID. * @param round The round. */ function _incrementUserDepositCount(uint256 roundId, Round storage round) private { uint256 userDepositCount = depositCount[roundId][msg.sender]; if (userDepositCount == 0) { uint256 numberOfParticipants = round.numberOfParticipants; if (numberOfParticipants == round.maximumNumberOfParticipants) { _revertWith(MaximumNumberOfParticipantsReached_error_selector); } unchecked { round.numberOfParticipants = uint40(numberOfParticipants + 1); } } unchecked { depositCount[roundId][msg.sender] = userDepositCount + 1; } } /** * @param round The round to check. */ function _setCutoffTimeIfNotSet(Round storage round) private { if (round.cutoffTime == 0) { round.cutoffTime = uint40(block.timestamp + roundDuration); } } /** * @dev This function is used to write the following values to the round: * - maximumNumberOfParticipants * - valuePerEntry * - protocolFeeBp * * roundValue can be provided to write other to other fields in the round. * @param roundId The round ID. * @param roundValue The starting round slot value to write to the round. * @return _valuePerEntry The round's value per entry in ETH. */ function _writeDataToRound(uint256 roundId, uint256 roundValue) private returns (uint256 _valuePerEntry) { // This is equivalent to // round.maximumNumberOfParticipants = maximumNumberOfParticipantsPerRound; // round.valuePerEntry = valuePerEntry; // round.protocolFeeBp = protocolFeeBp; uint256 _maximumNumberOfParticipantsPerRound = maximumNumberOfParticipantsPerRound; uint256 _protocolFeeBp = protocolFeeBp; _valuePerEntry = valuePerEntry; uint256 roundSlot = _getRoundSlot(roundId); assembly { roundValue := or( roundValue, shl(ROUND__MAXIMUM_NUMBER_OF_PARTICIPANTS_OFFSET, _maximumNumberOfParticipantsPerRound) ) roundValue := or(roundValue, shl(ROUND__PROTOCOL_FEE_BP_OFFSET, _protocolFeeBp)) sstore(roundSlot, roundValue) sstore( add(roundSlot, ROUND__VALUE_PER_ENTRY_SLOT_OFFSET), shl(ROUND__VALUE_PER_ENTRY_OFFSET, _valuePerEntry) ) } } /** * @param depositDataSlotWithCountOffset The deposit data slot with count offset. * @param currentEntryIndex The current entry index at the current deposit. */ function _writeDepositorAndCurrentEntryIndexToDeposit( uint256 depositDataSlotWithCountOffset, uint256 currentEntryIndex ) private { assembly { sstore( add(depositDataSlotWithCountOffset, DEPOSIT__LAST_SLOT_OFFSET), or(caller(), shl(DEPOSIT__CURRENT_ENTRY_INDEX_OFFSET, currentEntryIndex)) ) } } /** * @param depositDataSlotWithCountOffset The deposit data slot with count offset. * @param depositAmount The token amount to write to the deposit. */ function _writeDepositAmountToDeposit(uint256 depositDataSlotWithCountOffset, uint256 depositAmount) private { assembly { sstore(add(depositDataSlotWithCountOffset, DEPOSIT__TOKEN_AMOUNT_SLOT_OFFSET), depositAmount) } } /** * @param depositDataSlotWithCountOffset The deposit data slot with count offset. * @param tokenType The token type to write to the deposit. * @param tokenAddress The token address to write to the deposit. */ function _writeTokenAddressToDeposit( uint256 depositDataSlotWithCountOffset, YoloV2__TokenType tokenType, address tokenAddress ) private { assembly { sstore(depositDataSlotWithCountOffset, or(tokenType, shl(DEPOSIT__TOKEN_ADDRESS_OFFSET, tokenAddress))) } } /** * @param round The round to deposit ETH into. * @param roundId The round ID. * @param roundValuePerEntry The value of each entry in ETH. * @param depositAmount The amount of ETH to deposit. * @return entriesCount The number of entries for the deposit amount. */ function _depositETH( Round storage round, uint256 roundId, uint256 roundValuePerEntry, uint256 depositAmount ) private returns (uint256 entriesCount) { entriesCount = depositAmount / roundValuePerEntry; uint256 roundDepositCount = round.deposits.length; uint256 roundDepositCountAfterDeposit = _unsafeAdd(roundDepositCount, 1); _validateRoundDepositsAndPlayers(roundDepositCountAfterDeposit, round.numberOfParticipants); uint40 currentEntryIndex = _getCurrentEntryIndexWithoutAccrual(round, roundDepositCount, entriesCount); // This is equivalent to // round.deposits.push( // Deposit({ // tokenType: YoloV2__TokenType.ETH, // tokenAddress: address(0), // tokenId: 0, // tokenAmount: msg.value, // depositor: msg.sender, // withdrawn: false, // currentEntryIndex: currentEntryIndex // }) // ); // unchecked { // roundDepositCount += 1; // } uint256 roundDepositsLengthSlot = _getRoundSlot(roundId) + ROUND__DEPOSITS_LENGTH_SLOT_OFFSET; uint256 depositDataSlotWithCountOffset = _getDepositDataSlotWithCountOffset( roundDepositsLengthSlot, roundDepositCount ); // We don't have to write tokenType, tokenAddress, tokenId, and withdrawn because they are 0. _writeDepositorAndCurrentEntryIndexToDeposit(depositDataSlotWithCountOffset, currentEntryIndex); _writeDepositAmountToDeposit(depositDataSlotWithCountOffset, depositAmount); assembly { sstore(roundDepositsLengthSlot, roundDepositCountAfterDeposit) } } /** * @param singleDeposit The deposit to withdraw from. * @param transferAccumulator The ERC-20 transfer accumulator so far. * @param ethAmount The ETH amount so far. * @return The new ETH amount. */ function _transferTokenOut( Deposit storage singleDeposit, TransferAccumulator memory transferAccumulator, uint256 ethAmount ) private returns (uint256) { _validateDepositNotWithdrawn(singleDeposit); singleDeposit.withdrawn = true; YoloV2__TokenType tokenType = singleDeposit.tokenType; if (tokenType == YoloV2__TokenType.ETH) { ethAmount += singleDeposit.tokenAmount; } else if (tokenType == YoloV2__TokenType.ERC721) { _executeERC721TransferFrom(singleDeposit.tokenAddress, address(this), msg.sender, singleDeposit.tokenId); } else if (tokenType == YoloV2__TokenType.ERC20) { address tokenAddress = singleDeposit.tokenAddress; if (tokenAddress == transferAccumulator.tokenAddress) { transferAccumulator.amount += singleDeposit.tokenAmount; } else { if (transferAccumulator.amount != 0) { _executeERC20DirectTransfer( transferAccumulator.tokenAddress, msg.sender, transferAccumulator.amount ); } transferAccumulator.tokenAddress = tokenAddress; transferAccumulator.amount = singleDeposit.tokenAmount; } } return ethAmount; } /** * @param protocolFeeOwed Protocol fee owed in ETH. */ function _payForProtocolFeesInLOOKS(uint256 protocolFeeOwed) private { protocolFeeOwed = _protocolFeeOwedInLOOKS(protocolFeeOwed); transferManager.transferERC20(LOOKS, msg.sender, protocolFeeRecipient, protocolFeeOwed); emit ProtocolFeePayment(protocolFeeOwed, LOOKS); } /** * @param protocolFeeOwed Protocol fee owed in ETH. */ function _payForProtocolFeesInETH(uint256 protocolFeeOwed) private { _transferETHAndWrapIfFailWithGasLimit(WETH, protocolFeeRecipient, protocolFeeOwed, gasleft()); emit ProtocolFeePayment(protocolFeeOwed, address(0)); } function _validateIsOwner() private view { if (!hasRole(DEFAULT_ADMIN_ROLE, msg.sender)) { _revertWith(NotOwner_error_selector); } } function _validateIsOperator() private view { if (!hasRole(OPERATOR_ROLE, msg.sender)) { _revertWith(NotOperator_error_selector); } } /** * @param round The round to check the status of. * @param status The expected status of the round */ function _validateRoundStatus(Round storage round, RoundStatus status) private view { if (round.status != status) { _revertWithInvalidStatus(); } } /** * @param round The round to check the status and cutoffTime of. */ function _validateRoundIsOpen(Round storage round) private view { if (round.status != RoundStatus.Open || (round.cutoffTime != 0 && block.timestamp >= round.cutoffTime)) { _revertWithInvalidStatus(); } } /** * @param singleDeposit The deposit to withdraw from. */ function _validateDepositNotWithdrawn(Deposit storage singleDeposit) private view { if (singleDeposit.withdrawn) { _revertWith(AlreadyWithdrawn_error_selector); } } /** * @param length The length of the array. */ function _validateArrayLengthIsNotEmpty(uint256 length) private pure { if (length == 0) { _revertWith(InvalidLength_error_selector); } } function _validateOutflowIsAllowed() private view { if (!outflowAllowed) { _revertWith(OutflowNotAllowed_error_selector); } } /** * @param index The array index. * @param roundDepositsLength The round's number of deposits. */ function _validateDepositsArrayIndex(uint256 index, uint256 roundDepositsLength) private pure { if (index >= roundDepositsLength) { _revertWith(InvalidIndex_error_selector); } } /** * @param singleDeposit The deposit to check the depositor of. */ function _validateMsgSenderIsDepositor(Deposit storage singleDeposit) private view { if (msg.sender != singleDeposit.depositor) { _revertWith(NotDepositor_error_selector); } } /** * @param round The round to check the winner of. */ function _validateMsgSenderIsWinner(Round storage round) private view { if (msg.sender != round.winner) { _revertWith(NotWinner_error_selector); } } /** * @param entriesCount The number of entries to be added. */ function _validateNonZeroEntries(uint256 entriesCount) private pure { if (entriesCount == 0) { _revertWith(ZeroEntries_error_selector); } } /** * @param errorSelector The uint256 representation of the error's 4 bytes selector. */ function _revertWith(uint256 errorSelector) private pure { assembly { mstore(0x00, errorSelector) revert(Error_selector_offset, Error_standard_length) } } function _revertWithInvalidStatus() private pure { _revertWith(InvalidStatus_error_selector); } function _revertWithInvalidToken() private pure { _revertWith(InvalidToken_error_selector); } function _revertWithInvalidValue() private pure { _revertWith(InvalidValue_error_selector); } /** * @param roundDepositCount The number of deposits in the round. * @param numberOfParticipants The number of participants in the round. */ function _validateRoundDepositsAndPlayers(uint256 roundDepositCount, uint256 numberOfParticipants) private pure { if (roundDepositCount > MAXIMUM_NUMBER_OF_DEPOSITS_PER_ROUND) { _revertWith(MaximumNumberOfDepositsReached_error_selector); } if (roundDepositCount == MAXIMUM_NUMBER_OF_DEPOSITS_PER_ROUND) { if (numberOfParticipants == 1) { _revertWith(OnePlayerCannotFillUpTheWholeRound_error_selector); } } } /** * @param collection The collection address. * @param floorPrice The floor price response from Reservoir oracle. */ function _verifyReservoirSignature(address collection, ReservoirOracleFloorPrice calldata floorPrice) private view { if ( floorPrice.timestamp > block.timestamp || block.timestamp > floorPrice.timestamp + uint256(signatureValidityPeriod) ) { _revertWith(InvalidSignatureTimestamp_error_selector); } bytes32 expectedMessageId = keccak256( abi.encode(RESERVOIR_ORACLE_ID_TYPEHASH, uint8(1), TWAP_DURATION, collection, false) ); if (expectedMessageId != floorPrice.id) { _revertWith(MessageIdInvalid_error_selector); } bytes32 messageHash = keccak256( abi.encodePacked( "\x19Ethereum Signed Message:\n32", keccak256( abi.encode( RESERVOIR_ORACLE_MESSAGE_TYPEHASH, expectedMessageId, keccak256(floorPrice.payload), floorPrice.timestamp, block.chainid ) ) ) ); SignatureCheckerMemory.verify(messageHash, reservoirOracle, floorPrice.signature); } /** * @param singleDeposit The ERC-721 deposit to get the price of. * @return price The price decoded from the Reservoir oracle payload. */ function _getReservoirPrice(DepositCalldata calldata singleDeposit) private view returns (uint256 price) { address token; ReservoirOracleFloorPrice calldata reservoirOracleFloorPrice = singleDeposit.reservoirOracleFloorPrice; _verifyReservoirSignature(singleDeposit.tokenAddress, reservoirOracleFloorPrice); (token, price) = abi.decode(reservoirOracleFloorPrice.payload, (address, uint256)); if (token != address(0)) { _revertWithInvalidToken(); } } /** * @param currentEntryIndex The round's current entry index. * @param entriesCount The number of entries to be added. * @param round The open round. * @param roundDepositCount The number of deposits in the round. * @return The new current entry index. */ function _incrementCurrentEntryIndex( uint40 currentEntryIndex, uint256 entriesCount, Round storage round, uint256 roundDepositCount ) private view returns (uint40) { if (currentEntryIndex != 0) { return currentEntryIndex + uint40(entriesCount); } else { return _getCurrentEntryIndexWithoutAccrual(round, roundDepositCount, entriesCount); } } /** * @param round The open round. * @param roundDepositCount The number of deposits in the round. * @param entriesCount The number of entries to be added. * @return currentEntryIndex The current entry index after adding entries count. */ function _getCurrentEntryIndexWithoutAccrual( Round storage round, uint256 roundDepositCount, uint256 entriesCount ) private view returns (uint40 currentEntryIndex) { _validateNonZeroEntries(entriesCount); if (roundDepositCount == 0) { currentEntryIndex = uint40(entriesCount); } else { currentEntryIndex = uint40( round.deposits[_unsafeSubtract(roundDepositCount, 1)].currentEntryIndex + entriesCount ); } } /** * @param protocolFeeOwedInETH The protocol fee owed in ETH. * @return protocolFeeOwedInLOOKS The protocol fee owed in LOOKS. */ function _protocolFeeOwedInLOOKS( uint256 protocolFeeOwedInETH ) private view returns (uint256 protocolFeeOwedInLOOKS) { protocolFeeOwedInLOOKS = (1e18 * protocolFeeOwedInETH * discountedProtocolFeeBp) / _getTWAP(LOOKS) / 10_000; } /** * @param tokenAddress The token address to get the TWAP price in. */ function _getTWAP(address tokenAddress) private view returns (uint256 price) { price = erc20Oracle.getTWAP(tokenAddress, uint32(TWAP_DURATION)); } /** * @param roundId The round ID. * @return roundSlot The round's starting storage slot. */ function _getRoundSlot(uint256 roundId) private pure returns (uint256 roundSlot) { assembly { mstore(0x00, roundId) mstore(0x20, rounds.slot) roundSlot := keccak256(0x00, 0x40) } } /** * @param roundDepositsLengthSlot The round's deposits length slot. * @param roundDepositCount The number of deposits in the round. * @return depositDataSlotWithCountOffset The round's next deposit's starting storage slot. */ function _getDepositDataSlotWithCountOffset( uint256 roundDepositsLengthSlot, uint256 roundDepositCount ) private pure returns (uint256 depositDataSlotWithCountOffset) { assembly { mstore(0x00, roundDepositsLengthSlot) let depositsDataSlot := keccak256(0x00, 0x20) depositDataSlotWithCountOffset := add(depositsDataSlot, mul(DEPOSIT__OCCUPIED_SLOTS, roundDepositCount)) } } /** * @param numberOfParticipants The number of participants in the round. * @param maximumNumberOfParticipants The maximum number of participants in the round. * @param roundDepositCount The number of deposits in the round. */ function _shouldDrawWinner( uint256 numberOfParticipants, uint256 maximumNumberOfParticipants, uint256 roundDepositCount ) private pure returns (bool shouldDraw) { shouldDraw = numberOfParticipants >= maximumNumberOfParticipants || (numberOfParticipants > 1 && roundDepositCount >= MAXIMUM_NUMBER_OF_DEPOSITS_PER_ROUND); } /** * 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.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; /** * @notice This returns whether the user has approved the operator address. * The first address is the user and the second address is the operator. */ function hasUserApprovedOperator(address user, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; enum TokenType { ERC20, ERC721, ERC1155 }
// 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); function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; // Interfaces import {IERC1271} from "./interfaces/generic/IERC1271.sol"; // Constants import {ERC1271_MAGIC_VALUE} from "./constants/StandardConstants.sol"; // Errors import {SignatureParameterSInvalid, SignatureParameterVInvalid, SignatureERC1271Invalid, SignatureEOAInvalid, NullSignerAddress, SignatureLengthInvalid} from "./errors/SignatureCheckerErrors.sol"; /** * @title SignatureCheckerMemory * @notice This library is used to verify signatures for EOAs (with lengths of both 65 and 64 bytes) * and contracts (ERC1271). * @author LooksRare protocol team (👀,💎) */ library SignatureCheckerMemory { /** * @notice This function verifies whether the signer is valid for a hash and raw signature. * @param hash Data hash * @param signer Signer address (to confirm message validity) * @param signature Signature parameters encoded (v, r, s) * @dev For EIP-712 signatures, the hash must be the digest (computed with signature hash and domain separator) */ function verify(bytes32 hash, address signer, bytes memory signature) internal view { if (signer.code.length == 0) { if (_recoverEOASigner(hash, signature) == signer) return; revert SignatureEOAInvalid(); } else { if (IERC1271(signer).isValidSignature(hash, signature) == ERC1271_MAGIC_VALUE) return; revert SignatureERC1271Invalid(); } } /** * @notice This function is internal and splits a signature into r, s, v outputs. * @param signature A 64 or 65 bytes signature * @return r The r output of the signature * @return s The s output of the signature * @return v The recovery identifier, must be 27 or 28 */ function splitSignature(bytes memory signature) internal pure returns (bytes32 r, bytes32 s, uint8 v) { uint256 length = signature.length; if (length == 65) { assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } } else if (length == 64) { assembly { r := mload(add(signature, 0x20)) let vs := mload(add(signature, 0x40)) s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) v := add(shr(255, vs), 27) } } else { revert SignatureLengthInvalid(length); } if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { revert SignatureParameterSInvalid(); } if (v != 27 && v != 28) { revert SignatureParameterVInvalid(v); } } /** * @notice This function is private and recovers the signer of a signature (for EOA only). * @param hash Hash of the signed message * @param signature Bytes containing the signature (64 or 65 bytes) * @return signer The address that signed the signature */ function _recoverEOASigner(bytes32 hash, bytes memory signature) private pure returns (address signer) { (bytes32 r, bytes32 s, uint8 v) = splitSignature(signature); // If the signature is valid (and not malleable), return the signer's address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { revert NullSignerAddress(); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; // Interfaces import {IReentrancyGuard} from "./interfaces/IReentrancyGuard.sol"; /** * @title ReentrancyGuard * @notice This contract protects against reentrancy attacks. * It is adjusted from OpenZeppelin. * @author LooksRare protocol team (👀,💎) */ abstract contract ReentrancyGuard is IReentrancyGuard { uint256 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.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 // OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol) pragma solidity ^0.8.0; import "./IAccessControl.sol"; import "../utils/Context.sol"; import "../utils/Strings.sol"; import "../utils/introspection/ERC165.sol"; /** * @dev Contract module that allows children to implement role-based access * control mechanisms. This is a lightweight version that doesn't allow enumerating role * members except through off-chain means by accessing the contract event logs. Some * applications may benefit from on-chain enumerability, for those cases see * {AccessControlEnumerable}. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ```solidity * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ```solidity * function foo() public { * require(hasRole(MY_ROLE, msg.sender)); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. * * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to * grant and revoke this role. Extra precautions should be taken to secure * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} * to enforce additional security measures for this role. */ abstract contract AccessControl is Context, IAccessControl, ERC165 { struct RoleData { mapping(address => bool) members; bytes32 adminRole; } mapping(bytes32 => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Modifier that checks that an account has a specific role. Reverts * with a standardized message including the required role. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ * * _Available since v4.1._ */ modifier onlyRole(bytes32 role) { _checkRole(role); _; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view virtual override returns (bool) { return _roles[role].members[account]; } /** * @dev Revert with a standard message if `_msgSender()` is missing `role`. * Overriding this function changes the behavior of the {onlyRole} modifier. * * Format of the revert message is described in {_checkRole}. * * _Available since v4.6._ */ function _checkRole(bytes32 role) internal view virtual { _checkRole(role, _msgSender()); } /** * @dev Revert with a standard message if `account` is missing `role`. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ */ function _checkRole(bytes32 role, address account) internal view virtual { if (!hasRole(role, account)) { revert( string( abi.encodePacked( "AccessControl: account ", Strings.toHexString(account), " is missing role ", Strings.toHexString(uint256(role), 32) ) ) ); } } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) { return _roles[role].adminRole; } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleGranted} event. */ function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _grantRole(role, account); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleRevoked} event. */ function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _revokeRole(role, account); } /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been revoked `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. * * May emit a {RoleRevoked} event. */ function renounceRole(bytes32 role, address account) public virtual override { require(account == _msgSender(), "AccessControl: can only renounce roles for self"); _revokeRole(role, account); } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. Note that unlike {grantRole}, this function doesn't perform any * checks on the calling account. * * May emit a {RoleGranted} event. * * [WARNING] * ==== * This function should only be called from the constructor when setting * up the initial roles for the system. * * Using this function in any other way is effectively circumventing the admin * system imposed by {AccessControl}. * ==== * * NOTE: This function is deprecated in favor of {_grantRole}. */ function _setupRole(bytes32 role, address account) internal virtual { _grantRole(role, account); } /** * @dev Sets `adminRole` as ``role``'s admin role. * * Emits a {RoleAdminChanged} event. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { bytes32 previousAdminRole = getRoleAdmin(role); _roles[role].adminRole = adminRole; emit RoleAdminChanged(role, previousAdminRole, adminRole); } /** * @dev Grants `role` to `account`. * * Internal function without access restriction. * * May emit a {RoleGranted} event. */ function _grantRole(bytes32 role, address account) internal virtual { if (!hasRole(role, account)) { _roles[role].members[account] = true; emit RoleGranted(role, account, _msgSender()); } } /** * @dev Revokes `role` from `account`. * * Internal function without access restriction. * * May emit a {RoleRevoked} event. */ function _revokeRole(bytes32 role, address account) internal virtual { if (hasRole(role, account)) { _roles[role].members[account] = false; emit RoleRevoked(role, account, _msgSender()); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface 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.23; interface IYoloV2 { /** * @notice A round's status * @param None The round does not exist * @param Open The round is open for deposits * @param Drawing The round is being drawn * @param Drawn The round has been drawn * @param Cancelled The round has been cancelled */ enum RoundStatus { None, Open, Drawing, Drawn, Cancelled } /** * @dev Giving TokenType a namespace to avoid name conflicts with TransferManager. */ enum YoloV2__TokenType { ETH, ERC20, ERC721 } event TokensStatusUpdated(address[] tokens, YoloV2__TokenType tokenType, bool isAllowed); event Deposited(address depositor, uint256 roundId, uint256 entriesCount); event ERC20OracleUpdated(address erc20Oracle); event MaximumNumberOfParticipantsPerRoundUpdated(uint40 maximumNumberOfParticipantsPerRound); event MultipleRoundsDeposited( address depositor, uint256 startingRoundId, uint256[] amounts, uint256[] entriesCounts ); event PrizesClaimed(address winner, WithdrawalCalldata[] withdrawalCalldata); event DepositsWithdrawn(address depositor, WithdrawalCalldata[] withdrawalCalldata); event Rollover( address depositor, WithdrawalCalldata[] withdrawalCalldata, uint256 enteredRoundId, uint256 entriesCount ); event ProtocolFeeBpUpdated(uint16 protocolFeeBp); event DiscountedProtocolFeeBpUpdated(uint16 discountedProtocolFeeBp); event ProtocolFeePayment(uint256 amount, address token); event ProtocolFeeRecipientUpdated(address protocolFeeRecipient); event RandomnessRequested(uint256 roundId, uint256 requestId); event ReservoirOracleUpdated(address reservoirOracle); event RoundDurationUpdated(uint40 roundDuration); event RoundsCancelled(uint256 startingRoundId, uint256 numberOfRounds); event RoundStatusUpdated(uint256 roundId, RoundStatus status); event SignatureValidityPeriodUpdated(uint40 signatureValidityPeriod); event ValuePerEntryUpdated(uint256 valuePerEntry); event OutflowAllowedUpdated(bool isAllowed); error AlreadyWithdrawn(); error CutoffTimeNotReached(); error DrawExpirationTimeNotReached(); error InsufficientParticipants(); error InvalidIndex(); error InvalidLength(); error InvalidSignatureTimestamp(); error InvalidStatus(); error InvalidToken(); error InvalidTokenType(); error InvalidValue(); error LooksAlreadySet(); error MaximumNumberOfDepositsReached(); error MaximumNumberOfParticipantsReached(); error MessageIdInvalid(); error NotOperator(); error NotOwner(); error NotWinner(); error NotDepositor(); error OnePlayerCannotFillUpTheWholeRound(); error OutflowNotAllowed(); error ProtocolFeeNotPaid(); error RandomnessRequestAlreadyExists(); error RoundCannotBeClosed(); error TooFewEntries(); error ZeroDeposits(); error ZeroEntries(); error ZeroRounds(); /** * @param owner The owner of the contract. * @param operator The operator of the contract. * @param roundDuration The duration of each round. * @param valuePerEntry The value of each entry in ETH. * @param protocolFeeRecipient The protocol fee recipient. * @param protocolFeeBp The protocol fee basis points. * @param discountedProtocolFeeBp The discounted protocol fee basis points. * @param keyHash Chainlink VRF key hash * @param subscriptionId Chainlink VRF subscription ID * @param vrfCoordinator Chainlink VRF coordinator address * @param reservoirOracle Reservoir off-chain oracle address * @param erc20Oracle ERC20 on-chain oracle address * @param transferManager Transfer manager * @param signatureValidityPeriod The validity period of a Reservoir signature. * @param minimumRequestConfirmations The minimum number of confirmation blocks on VRF requests before oracles respond. */ struct ConstructorCalldata { address owner; address operator; uint40 maximumNumberOfParticipantsPerRound; uint40 roundDuration; uint96 valuePerEntry; address protocolFeeRecipient; uint16 protocolFeeBp; uint16 discountedProtocolFeeBp; bytes32 keyHash; uint64 subscriptionId; address vrfCoordinator; address reservoirOracle; address transferManager; address erc20Oracle; address weth; uint40 signatureValidityPeriod; uint16 minimumRequestConfirmations; } /** * @param id The id of the response. * @param payload The payload of the response. * @param timestamp The timestamp of the response. * @param signature The signature of the response. */ struct ReservoirOracleFloorPrice { bytes32 id; bytes payload; uint256 timestamp; bytes signature; } /** * @param tokenType The type of the token. * @param tokenAddress The address of the token. * @param tokenIdsOrAmounts The ids (ERC-721) or amounts (ERC-20) of the tokens. * @param minimumEntries The minimum entries to receive if it's an ERC-20 deposit. Unused for ERC-721 deposits. * @param reservoirOracleFloorPrice The Reservoir oracle floor price. Required for ERC-721 deposits. */ struct DepositCalldata { YoloV2__TokenType tokenType; address tokenAddress; uint256[] tokenIdsOrAmounts; uint256 minimumEntries; ReservoirOracleFloorPrice reservoirOracleFloorPrice; } /* * @notice A round * @dev The storage layout of a round is as follows: * |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| * | empty (72 bits) | numberOfParticipants (40) bits) | drawnAt (40 bits) | cutoffTime (40 bits) | protcoolFeeBp (16 bits) | maximumNumberOfParticipants (40 bits) | status (8 bits) | * |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| * | valuePerEntry (96 bits) | winner (160 bits) | * |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| * | protocolFeeOwed (256 bits) | * |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| * | deposits length (256 bits) | * |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| * * @param status The status of the round. * @param maximumNumberOfParticipants The maximum number of participants. * @param protocolFeeBp The protocol fee basis points. * @param cutoffTime The cutoff time of the round. * @param drawnAt The time the round was drawn. * @param numberOfParticipants The current number of participants. * @param winner The winner of the round. * @param valuePerEntry The value of each entry in ETH. * @param protocolFeeOwed The protocol fee owed in ETH. * @param deposits The deposits in the round. */ struct Round { RoundStatus status; uint40 maximumNumberOfParticipants; uint16 protocolFeeBp; uint40 cutoffTime; uint40 drawnAt; uint40 numberOfParticipants; address winner; uint96 valuePerEntry; uint256 protocolFeeOwed; Deposit[] deposits; } /** * @notice A deposit in a round. * @dev The storage layout of a deposit is as follows: * |-------------------------------------------------------------------------------------------| * | empty (88 bits) | tokenAddress (160 bits) | tokenType (8 bits) | * |-------------------------------------------------------------------------------------------| * | tokenId (256 bits) | * |-------------------------------------------------------------------------------------------| * | tokenAmount (256 bits) | * |-------------------------------------------------------------------------------------------| * | empty (48 bits) | currentEntryIndex (40 bits) | withdrawn (8 bits) | depositor (160 bits) | * |-------------------------------------------------------------------------------------------| * * @param tokenType The type of the token. * @param tokenAddress The address of the token. * @param tokenId The id of the token. * @param tokenAmount The amount of the token. * @param depositor The depositor of the token. * @param withdrawn Whether the token has been withdrawn. * @param currentEntryIndex The current entry index. */ struct Deposit { YoloV2__TokenType tokenType; address tokenAddress; uint256 tokenId; uint256 tokenAmount; address depositor; bool withdrawn; uint40 currentEntryIndex; } /** * @param exists Whether the request exists. * @param roundId The id of the round. * @param randomWord The random words returned by Chainlink VRF. * If randomWord == 0, then the request is still pending. */ struct RandomnessRequest { bool exists; uint40 roundId; uint256 randomWord; } /** * @param roundId The id of the round. * @param depositIndices The indices of the deposits to be claimed. */ struct WithdrawalCalldata { uint256 roundId; uint256[] depositIndices; } /** * @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; } /** * @notice This function cancels an expired round that does not have at least 2 participants. */ function cancel() external; /** * @notice This function cancels multiple rounds (current and future) without any validations (can be any state). * Only callable by the contract owner. * @param numberOfRounds Number of rounds to cancel. */ function cancel(uint256 numberOfRounds) external; /** * @notice Cancels a round after randomness request if the randomness request * does not arrive after 25 hours. Chainlink VRF stops trying after 24 hours. * Giving an extra hour should prevent any frontrun attempts. */ function cancelAfterRandomnessRequest() external; /** * @notice This function allows the winner of a round to withdraw the prizes. * @param withdrawalCalldata The rounds and the indices for the rounds for the prizes to claim. * @param payWithLOOKS Whether to pay for the protocol fee with LOOKS. */ function claimPrizes(WithdrawalCalldata[] calldata withdrawalCalldata, bool payWithLOOKS) external payable; /** * @notice This function calculates the ETH payment required to claim the prizes for multiple rounds. * @param withdrawalCalldata The rounds and the indices for the rounds for the prizes to claim. * @param payWithLOOKS Whether to pay for the protocol fee with LOOKS. * @return protocolFeeOwed The protocol fee owed in ETH or LOOKS. */ function getClaimPrizesPaymentRequired( WithdrawalCalldata[] calldata withdrawalCalldata, bool payWithLOOKS ) external view returns (uint256 protocolFeeOwed); /** * @notice This function is used by the frontend to estimate the minimumEntries to be set for ERC-20 deposits. * @dev This function does 0 validations. It is the responsibility of the caller to ensure that the deposit is valid and the round is enterable. * @param roundId The round ID. * @param singleDeposit The ERC-20 deposit. * @return entriesCount The estimated number of entries for the deposit amount. */ function estimatedERC20DepositEntriesCount( uint256 roundId, DepositCalldata calldata singleDeposit ) external view returns (uint256 entriesCount); /** * @notice This function allows withdrawal of deposits from a round if the round is cancelled * @param withdrawalCalldata The rounds and the indices for the rounds for the prizes to claim. */ function withdrawDeposits(WithdrawalCalldata[] calldata withdrawalCalldata) external; /** * @notice This function allows players to deposit into a round. * @param roundId The open round ID. * @param deposits The ERC-20/ERC-721 deposits to be made. */ function deposit(uint256 roundId, DepositCalldata[] calldata deposits) external payable; /** * @notice This function allows a player to deposit into multiple rounds at once. ETH only. * @param startingRoundId The starting round ID to deposit into. Round status must be Open. * @param amounts The amount of ETH to deposit into each round. */ function depositETHIntoMultipleRounds(uint256 startingRoundId, uint256[] calldata amounts) external payable; /** * @notice This function draws a round. */ function drawWinner() external; /** * @notice This function returns the given round's data. * @param roundId The round ID. * @return status The status of the round. * @return maximumNumberOfParticipants The round's maximum number of participants. * @return roundProtocolFeeBp The round's protocol fee in basis points. * @return cutoffTime The round's cutoff time. * @return drawnAt The time the round was drawn. * @return numberOfParticipants The round's current number of participants. * @return winner The round's winner. * @return roundValuePerEntry The round's value per entry. * @return protocolFeeOwed The round's protocol fee owed in ETH. * @return deposits The round's deposits. */ function getRound( uint256 roundId ) external view returns ( IYoloV2.RoundStatus status, uint40 maximumNumberOfParticipants, uint16 roundProtocolFeeBp, uint40 cutoffTime, uint40 drawnAt, uint40 numberOfParticipants, address winner, uint96 roundValuePerEntry, uint256 protocolFeeOwed, Deposit[] memory deposits ); /** * @notice This function allows a player to rollover prizes or deposits from a cancelled round to the current round. * @param roundId The round ID to rollover ETH into. * @param withdrawalCalldata The rounds and the indices for the rounds for the prizes to claim. * @param payWithLOOKS Whether to pay for the protocol fee with LOOKS. */ function rolloverETH(uint256 roundId, WithdrawalCalldata[] calldata withdrawalCalldata, bool payWithLOOKS) external; /** * @notice This function allows the owner to pause/unpause the contract. */ function togglePaused() external; /** * @notice This function allows the owner to allow/forbid token outflow. */ function toggleOutflowAllowed() external; /** * @notice This function allows the owner to update token statuses (ERC-20 and ERC-721). * @param tokens Token addresses * @param tokenType Token type * @param isAllowed Whether the tokens should be allowed in the yolos * @dev Only callable by owner. */ function updateTokensStatus(address[] calldata tokens, YoloV2__TokenType tokenType, bool isAllowed) external; /** * @notice This function allows the owner to update the duration of each round. * @param _roundDuration The duration of each round. */ function updateRoundDuration(uint40 _roundDuration) external; /** * @notice This function allows the owner to update the signature validity period. * @param _signatureValidityPeriod The signature validity period. */ function updateSignatureValidityPeriod(uint40 _signatureValidityPeriod) external; /** * @notice This function allows the owner to update the value of each entry in ETH. * @param _valuePerEntry The value of each entry in ETH. */ function updateValuePerEntry(uint96 _valuePerEntry) external; /** * @notice This function allows the owner to update the discounted protocol fee in basis points if paid in LOOKS. * @param discountedProtocolFeeBp The discounted protocol fee in basis points. */ function updateDiscountedProtocolFeeBp(uint16 discountedProtocolFeeBp) external; /** * @notice This function allows the owner to update the protocol fee in basis points. * @param protocolFeeBp The protocol fee in basis points. */ function updateProtocolFeeBp(uint16 protocolFeeBp) external; /** * @notice This function allows the owner to update the protocol fee recipient. * @param protocolFeeRecipient The protocol fee recipient. */ function updateProtocolFeeRecipient(address protocolFeeRecipient) external; /** * @notice This function allows the owner to update Reservoir oracle's address. * @param reservoirOracle Reservoir oracle address. */ function updateReservoirOracle(address reservoirOracle) external; /** * @notice This function allows the owner to update the maximum number of participants per round. * @param _maximumNumberOfParticipantsPerRound The maximum number of participants per round. */ function updateMaximumNumberOfParticipantsPerRound(uint40 _maximumNumberOfParticipantsPerRound) external; /** * @notice This function allows the owner to update ERC20 oracle's address. * @param erc20Oracle ERC20 oracle address. */ function updateERC20Oracle(address erc20Oracle) external; /** * @notice This function allows the owner to set the LOOKS token address. Only callable once. * @param looks LOOKS token address. */ function setLOOKS(address looks) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; interface IPriceOracle { error PoolNotAllowed(); error PriceIsZero(); event PoolAdded(address token, address pool); event PoolRemoved(address token); function getTWAP(address token, uint32 secondsAgo) external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; 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.23; /* * @dev error AlreadyWithdrawn() * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant AlreadyWithdrawn_error_selector = 0x6507689f; /* * @dev error CutoffTimeNotReached() * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant CutoffTimeNotReached_error_selector = 0xf9ad93f5; /* * @dev error DrawExpirationTimeNotReached() * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant DrawExpirationTimeNotReached_error_selector = 0xf4c0ca6e; /* * @dev error InsufficientParticipants() * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant InsufficientParticipants_error_selector = 0x7e439aed; /* * @dev error InvalidIndex() * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant InvalidIndex_error_selector = 0x63df8171; /* * @dev error InvalidLength() * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant InvalidLength_error_selector = 0x947d5a84; /* * @dev error InvalidSignatureTimestamp() * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant InvalidSignatureTimestamp_error_selector = 0xc11f5976; /* * @dev error InvalidStatus() * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant InvalidStatus_error_selector = 0xf525e320; /* * @dev error InvalidToken() * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant InvalidToken_error_selector = 0xc1ab6dc1; /* * @dev error InvalidTokenType() * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant InvalidTokenType_error_selector = 0xa1e9dd9d; /* * @dev error InvalidValue() * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant InvalidValue_error_selector = 0xaa7feadc; /* * @dev error LooksAlreadySet() * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant LooksAlreadySet_error_selector = 0xd6336f0d; /* * @dev error MaximumNumberOfDepositsReached() * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant MaximumNumberOfDepositsReached_error_selector = 0x27e6fcc7; /* * @dev error MaximumNumberOfParticipantsReached() * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant MaximumNumberOfParticipantsReached_error_selector = 0xb53a57db; /* * @dev error MessageIdInvalid() * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant MessageIdInvalid_error_selector = 0x0da5618b; /* * @dev error NotDepositor() * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant NotDepositor_error_selector = 0x3cc50b45; /* * @dev error NotOwner() * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant NotOwner_error_selector = 0x30cd7471; /* * @dev error NotOperator() * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant NotOperator_error_selector = 0x7c214f04; /* * @dev error NotWinner() * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant NotWinner_error_selector = 0x618c7242; /* * @dev error OnePlayerCannotFillUpTheWholeRound() * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant OnePlayerCannotFillUpTheWholeRound_error_selector = 0xae24220e; /* * @dev error OutflowNotAllowed() * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant OutflowNotAllowed_error_selector = 0x010a265a; /* * @dev error ProtocolFeeNotPaid() * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant ProtocolFeeNotPaid_error_selector = 0x0134f278; /* * @dev error RandomnessRequestAlreadyExists() * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant RandomnessRequestAlreadyExists_error_selector = 0xf9012132; /* * @dev error RoundCannotBeClosed() * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant RoundCannotBeClosed_error_selector = 0x7cd9dd6a; /* * @dev error TooFewEntries() * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant TooFewEntries_error_selector = 0xf48cb8a0; /* * @dev error ZeroDeposits() * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant ZeroDeposits_error_selector = 0xa95231d5; /* * @dev error ZeroEntries() * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant ZeroEntries_error_selector = 0xf9121438; /* * @dev error ZeroRounds() * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant ZeroRounds_error_selector = 0xcbc4e060; uint256 constant Error_selector_offset = 0x1c; uint256 constant Error_standard_length = 0x04;
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; interface IERC1271 { function isValidSignature(bytes32 hash, bytes calldata signature) external view returns (bytes4 magicValue); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; /** * @dev ERC1271's magic value (bytes4(keccak256("isValidSignature(bytes32,bytes)")) */ bytes4 constant ERC1271_MAGIC_VALUE = 0x1626ba7e;
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; /** * @notice It is emitted if the signer is null. */ error NullSignerAddress(); /** * @notice It is emitted if the signature is invalid for an EOA (the address recovered is not the expected one). */ error SignatureEOAInvalid(); /** * @notice It is emitted if the signature is invalid for a ERC1271 contract signer. */ error SignatureERC1271Invalid(); /** * @notice It is emitted if the signature's length is neither 64 nor 65 bytes. */ error SignatureLengthInvalid(uint256 length); /** * @notice It is emitted if the signature is invalid due to S parameter. */ error SignatureParameterSInvalid(); /** * @notice It is emitted if the signature is invalid due to V parameter. */ error SignatureParameterVInvalid(uint8 v);
// 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.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; /** * @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 // OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) pragma solidity ^0.8.0; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControl { /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. * * _Available since v3.1._ */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {AccessControl-_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/Math.sol"; import "./math/SignedMath.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toString(int256 value) internal pure returns (string memory) { return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value)))); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1, "Math: mulDiv overflow"); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.0; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
{ "remappings": [ "@chainlink/=node_modules/@chainlink/", "@ensdomains/=node_modules/@ensdomains/", "@eth-optimism/=node_modules/@eth-optimism/", "@looksrare/=node_modules/@looksrare/", "@openzeppelin/=node_modules/@openzeppelin/", "@uniswap/=node_modules/@uniswap/", "base64-sol/=node_modules/base64-sol/", "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/", "vrf-contracts/=lib/vrf-contracts/contracts/" ], "optimizer": { "enabled": true, "runs": 888888 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "viaIR": true, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint40","name":"maximumNumberOfParticipantsPerRound","type":"uint40"},{"internalType":"uint40","name":"roundDuration","type":"uint40"},{"internalType":"uint96","name":"valuePerEntry","type":"uint96"},{"internalType":"address","name":"protocolFeeRecipient","type":"address"},{"internalType":"uint16","name":"protocolFeeBp","type":"uint16"},{"internalType":"uint16","name":"discountedProtocolFeeBp","type":"uint16"},{"internalType":"bytes32","name":"keyHash","type":"bytes32"},{"internalType":"uint64","name":"subscriptionId","type":"uint64"},{"internalType":"address","name":"vrfCoordinator","type":"address"},{"internalType":"address","name":"reservoirOracle","type":"address"},{"internalType":"address","name":"transferManager","type":"address"},{"internalType":"address","name":"erc20Oracle","type":"address"},{"internalType":"address","name":"weth","type":"address"},{"internalType":"uint40","name":"signatureValidityPeriod","type":"uint40"},{"internalType":"uint16","name":"minimumRequestConfirmations","type":"uint16"}],"internalType":"struct IYoloV2.ConstructorCalldata","name":"params","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyWithdrawn","type":"error"},{"inputs":[],"name":"CutoffTimeNotReached","type":"error"},{"inputs":[],"name":"DrawExpirationTimeNotReached","type":"error"},{"inputs":[],"name":"ERC20TransferFail","type":"error"},{"inputs":[],"name":"ERC721TransferFromFail","type":"error"},{"inputs":[],"name":"InsufficientParticipants","type":"error"},{"inputs":[],"name":"InvalidIndex","type":"error"},{"inputs":[],"name":"InvalidLength","type":"error"},{"inputs":[],"name":"InvalidSignatureTimestamp","type":"error"},{"inputs":[],"name":"InvalidStatus","type":"error"},{"inputs":[],"name":"InvalidToken","type":"error"},{"inputs":[],"name":"InvalidTokenType","type":"error"},{"inputs":[],"name":"InvalidValue","type":"error"},{"inputs":[],"name":"IsPaused","type":"error"},{"inputs":[],"name":"LooksAlreadySet","type":"error"},{"inputs":[],"name":"MaximumNumberOfDepositsReached","type":"error"},{"inputs":[],"name":"MaximumNumberOfParticipantsReached","type":"error"},{"inputs":[],"name":"MessageIdInvalid","type":"error"},{"inputs":[],"name":"NotAContract","type":"error"},{"inputs":[],"name":"NotDepositor","type":"error"},{"inputs":[],"name":"NotOperator","type":"error"},{"inputs":[],"name":"NotOwner","type":"error"},{"inputs":[],"name":"NotPaused","type":"error"},{"inputs":[],"name":"NotWinner","type":"error"},{"inputs":[],"name":"NullSignerAddress","type":"error"},{"inputs":[],"name":"OnePlayerCannotFillUpTheWholeRound","type":"error"},{"inputs":[{"internalType":"address","name":"have","type":"address"},{"internalType":"address","name":"want","type":"address"}],"name":"OnlyCoordinatorCanFulfill","type":"error"},{"inputs":[],"name":"OutflowNotAllowed","type":"error"},{"inputs":[],"name":"ProtocolFeeNotPaid","type":"error"},{"inputs":[],"name":"RandomnessRequestAlreadyExists","type":"error"},{"inputs":[],"name":"ReentrancyFail","type":"error"},{"inputs":[],"name":"RoundCannotBeClosed","type":"error"},{"inputs":[],"name":"SignatureEOAInvalid","type":"error"},{"inputs":[],"name":"SignatureERC1271Invalid","type":"error"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"name":"SignatureLengthInvalid","type":"error"},{"inputs":[],"name":"SignatureParameterSInvalid","type":"error"},{"inputs":[{"internalType":"uint8","name":"v","type":"uint8"}],"name":"SignatureParameterVInvalid","type":"error"},{"inputs":[],"name":"TooFewEntries","type":"error"},{"inputs":[],"name":"ZeroDeposits","type":"error"},{"inputs":[],"name":"ZeroEntries","type":"error"},{"inputs":[],"name":"ZeroRounds","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"depositor","type":"address"},{"indexed":false,"internalType":"uint256","name":"roundId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"entriesCount","type":"uint256"}],"name":"Deposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"depositor","type":"address"},{"components":[{"internalType":"uint256","name":"roundId","type":"uint256"},{"internalType":"uint256[]","name":"depositIndices","type":"uint256[]"}],"indexed":false,"internalType":"struct IYoloV2.WithdrawalCalldata[]","name":"withdrawalCalldata","type":"tuple[]"}],"name":"DepositsWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"discountedProtocolFeeBp","type":"uint16"}],"name":"DiscountedProtocolFeeBpUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"erc20Oracle","type":"address"}],"name":"ERC20OracleUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint40","name":"maximumNumberOfParticipantsPerRound","type":"uint40"}],"name":"MaximumNumberOfParticipantsPerRoundUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"depositor","type":"address"},{"indexed":false,"internalType":"uint256","name":"startingRoundId","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"entriesCounts","type":"uint256[]"}],"name":"MultipleRoundsDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isAllowed","type":"bool"}],"name":"OutflowAllowedUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"winner","type":"address"},{"components":[{"internalType":"uint256","name":"roundId","type":"uint256"},{"internalType":"uint256[]","name":"depositIndices","type":"uint256[]"}],"indexed":false,"internalType":"struct IYoloV2.WithdrawalCalldata[]","name":"withdrawalCalldata","type":"tuple[]"}],"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":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"token","type":"address"}],"name":"ProtocolFeePayment","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":"roundId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"requestId","type":"uint256"}],"name":"RandomnessRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"reservoirOracle","type":"address"}],"name":"ReservoirOracleUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"depositor","type":"address"},{"components":[{"internalType":"uint256","name":"roundId","type":"uint256"},{"internalType":"uint256[]","name":"depositIndices","type":"uint256[]"}],"indexed":false,"internalType":"struct IYoloV2.WithdrawalCalldata[]","name":"withdrawalCalldata","type":"tuple[]"},{"indexed":false,"internalType":"uint256","name":"enteredRoundId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"entriesCount","type":"uint256"}],"name":"Rollover","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint40","name":"roundDuration","type":"uint40"}],"name":"RoundDurationUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"roundId","type":"uint256"},{"indexed":false,"internalType":"enum IYoloV2.RoundStatus","name":"status","type":"uint8"}],"name":"RoundStatusUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"startingRoundId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"numberOfRounds","type":"uint256"}],"name":"RoundsCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint40","name":"signatureValidityPeriod","type":"uint40"}],"name":"SignatureValidityPeriodUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"tokens","type":"address[]"},{"indexed":false,"internalType":"enum IYoloV2.YoloV2__TokenType","name":"tokenType","type":"uint8"},{"indexed":false,"internalType":"bool","name":"isAllowed","type":"bool"}],"name":"TokensStatusUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"valuePerEntry","type":"uint256"}],"name":"ValuePerEntryUpdated","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"numberOfRounds","type":"uint256"}],"name":"cancel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cancel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cancelAfterRandomnessRequest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"roundId","type":"uint256"},{"internalType":"uint256[]","name":"depositIndices","type":"uint256[]"}],"internalType":"struct IYoloV2.WithdrawalCalldata[]","name":"withdrawalCalldata","type":"tuple[]"},{"internalType":"bool","name":"payWithLOOKS","type":"bool"}],"name":"claimPrizes","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"roundId","type":"uint256"},{"components":[{"internalType":"enum IYoloV2.YoloV2__TokenType","name":"tokenType","type":"uint8"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256[]","name":"tokenIdsOrAmounts","type":"uint256[]"},{"internalType":"uint256","name":"minimumEntries","type":"uint256"},{"components":[{"internalType":"bytes32","name":"id","type":"bytes32"},{"internalType":"bytes","name":"payload","type":"bytes"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct IYoloV2.ReservoirOracleFloorPrice","name":"reservoirOracleFloorPrice","type":"tuple"}],"internalType":"struct IYoloV2.DepositCalldata[]","name":"deposits","type":"tuple[]"}],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"roundId","type":"uint256"},{"internalType":"address","name":"depositor","type":"address"}],"name":"depositCount","outputs":[{"internalType":"uint256","name":"depositCount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"startingRoundId","type":"uint256"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"depositETHIntoMultipleRounds","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"discountedProtocolFeeBp","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"drawWinner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"erc20Oracle","outputs":[{"internalType":"contract IPriceOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"roundId","type":"uint256"},{"components":[{"internalType":"enum IYoloV2.YoloV2__TokenType","name":"tokenType","type":"uint8"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256[]","name":"tokenIdsOrAmounts","type":"uint256[]"},{"internalType":"uint256","name":"minimumEntries","type":"uint256"},{"components":[{"internalType":"bytes32","name":"id","type":"bytes32"},{"internalType":"bytes","name":"payload","type":"bytes"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct IYoloV2.ReservoirOracleFloorPrice","name":"reservoirOracleFloorPrice","type":"tuple"}],"internalType":"struct IYoloV2.DepositCalldata","name":"singleDeposit","type":"tuple"}],"name":"estimatedERC20DepositEntriesCount","outputs":[{"internalType":"uint256","name":"entriesCount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"roundId","type":"uint256"},{"internalType":"uint256[]","name":"depositIndices","type":"uint256[]"}],"internalType":"struct IYoloV2.WithdrawalCalldata[]","name":"withdrawalCalldata","type":"tuple[]"},{"internalType":"bool","name":"payWithLOOKS","type":"bool"}],"name":"getClaimPrizesPaymentRequired","outputs":[{"internalType":"uint256","name":"protocolFeeOwed","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"roundId","type":"uint256"}],"name":"getRound","outputs":[{"internalType":"enum IYoloV2.RoundStatus","name":"status","type":"uint8"},{"internalType":"uint40","name":"maximumNumberOfParticipants","type":"uint40"},{"internalType":"uint16","name":"roundProtocolFeeBp","type":"uint16"},{"internalType":"uint40","name":"cutoffTime","type":"uint40"},{"internalType":"uint40","name":"drawnAt","type":"uint40"},{"internalType":"uint40","name":"numberOfParticipants","type":"uint40"},{"internalType":"address","name":"winner","type":"address"},{"internalType":"uint96","name":"roundValuePerEntry","type":"uint96"},{"internalType":"uint256","name":"protocolFeeOwed","type":"uint256"},{"components":[{"internalType":"enum IYoloV2.YoloV2__TokenType","name":"tokenType","type":"uint8"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"internalType":"address","name":"depositor","type":"address"},{"internalType":"bool","name":"withdrawn","type":"bool"},{"internalType":"uint40","name":"currentEntryIndex","type":"uint40"}],"internalType":"struct IYoloV2.Deposit[]","name":"deposits","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maximumNumberOfParticipantsPerRound","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"outflowAllowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenOrCollection","type":"address"},{"internalType":"uint256","name":"roundId","type":"uint256"}],"name":"prices","outputs":[{"internalType":"uint256","name":"price","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeBp","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"requestId","type":"uint256"}],"name":"randomnessRequests","outputs":[{"internalType":"bool","name":"exists","type":"bool"},{"internalType":"uint40","name":"roundId","type":"uint40"},{"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":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"reservoirOracle","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"roundId","type":"uint256"},{"components":[{"internalType":"uint256","name":"roundId","type":"uint256"},{"internalType":"uint256[]","name":"depositIndices","type":"uint256[]"}],"internalType":"struct IYoloV2.WithdrawalCalldata[]","name":"withdrawalCalldata","type":"tuple[]"},{"internalType":"bool","name":"payWithLOOKS","type":"bool"}],"name":"rolloverETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"roundDuration","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"roundsCount","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"looks","type":"address"}],"name":"setLOOKS","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"signatureValidityPeriod","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"toggleOutflowAllowed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"togglePaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_discountedProtocolFeeBp","type":"uint16"}],"name":"updateDiscountedProtocolFeeBp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_erc20Oracle","type":"address"}],"name":"updateERC20Oracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint40","name":"_maximumNumberOfParticipantsPerRound","type":"uint40"}],"name":"updateMaximumNumberOfParticipantsPerRound","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_protocolFeeBp","type":"uint16"}],"name":"updateProtocolFeeBp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_protocolFeeRecipient","type":"address"}],"name":"updateProtocolFeeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_reservoirOracle","type":"address"}],"name":"updateReservoirOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint40","name":"_roundDuration","type":"uint40"}],"name":"updateRoundDuration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint40","name":"_signatureValidityPeriod","type":"uint40"}],"name":"updateSignatureValidityPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"enum IYoloV2.YoloV2__TokenType","name":"tokenType","type":"uint8"},{"internalType":"bool","name":"isAllowed","type":"bool"}],"name":"updateTokensStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint96","name":"_valuePerEntry","type":"uint96"}],"name":"updateValuePerEntry","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"valuePerEntry","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"roundId","type":"uint256"},{"internalType":"uint256[]","name":"depositIndices","type":"uint256[]"}],"internalType":"struct IYoloV2.WithdrawalCalldata[]","name":"withdrawalCalldata","type":"tuple[]"}],"name":"withdrawDeposits","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
6101608060405234620001e2576200667a610220813803918262000023816200021e565b938492833981010312620001e2576200003b620001e7565b91620000478262000244565b8352620000576020830162000244565b60208401526200006a6040830162000259565b60408401526200007d6060830162000259565b606084015262000090608083016200026c565b6080840152620000a360a0830162000244565b60a0840152620000b660c0830162000281565b60c0840152620000c960e0830162000281565b60e08401526200018361010093848401518582015261012093620000ef85820162000291565b85830152610140936200010485830162000244565b858401526200011581830162000244565b908301526101806200012981830162000244565b908301526101a06200013d81830162000244565b908301526101c06200015181830162000244565b908301526101e06200016581830162000259565b908301526200017961020080920162000281565b90820152620002a6565b60405191615bda938462000a608539608051846106b2015260a051848181610b4401528181611e7b0152614c77015260c051846147db015260e0518461480101525183614873015251826148310152518181816129880152614ccc0152f35b600080fd5b6040519061022082016001600160401b038111838210176200020857604052565b634e487b7160e01b600052604160045260246000fd5b6040519190601f01601f191682016001600160401b038111838210176200020857604052565b51906001600160a01b0382168203620001e257565b519064ffffffffff82168203620001e257565b51906001600160601b0382168203620001e257565b519061ffff82168203620001e257565b51906001600160401b0382168203620001e257565b620004746200043961018061014093848101620002d6620002cd825160018060a01b031690565b60805260018055565b600380546001600160f81b0316600160f81b179055815162000301906001600160a01b031662000483565b60208201516200031a906001600160a01b031662000514565b6200033762000331606084015164ffffffffff1690565b620005c8565b60a082015162000350906001600160a01b03166200064a565b6200036a6200036460c084015161ffff1690565b6200069a565b620003846200037e60e084015161ffff1690565b620006f7565b60808201516200039d906001600160601b031662000754565b6101a0820151620003b7906001600160a01b0316620007a4565b620003d4620003ce604084015164ffffffffff1690565b620007f4565b610160820151620003ee906001600160a01b031662000859565b6200040c620004066101e084015164ffffffffff1690565b620008a9565b6101c08201516001600160a01b031660a0526101008281015160c052905162000445906001600160a01b03165b6001600160a01b031690565b9052610120818101516001600160401b031660e05261020082015161ffff16905201516001600160a01b031690565b90526200048062000900565b50565b6001600160a01b03811660009081527fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5602052604081205460ff1615620004c8575050565b808052602081815260408083206001600160a01b038516600090815292529020805460ff1916600117905533916001600160a01b0316906000805160206200663a8339815191528180a4565b6001600160a01b03811660009081527fee57cd81e84075558e8fcc182a1f4393f91fc97f963a136e66b7f949a62f319f60205260408120547f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b9299060ff16156200057c57505050565b808252602082815260408084206001600160a01b038616600090815292529020805460ff1916600117905533926001600160a01b0316916000805160206200663a8339815191529080a4565b64ffffffffff811690610e1082116200063c577fbdeccc4cf4c928bfff2005eee2fd4b91bb3d22035af62a93e35b1eedf853e3a39160209170ffffffffff0000000000000000000000006003549160601b169070ffffffffff000000000000000000000000191617600355604051908152a1565b63aa7feadc6000526004601cfd5b6001600160a01b031680156200063c57600480546001600160a01b031916821790556040519081527fc1b5345cce283376356748dc57f2dfa7120431d016fc7ca9ba641bc65f91411d90602090a1565b61ffff8116906109c482116200063c576003805461ffff60881b191660889290921b61ffff60881b169190911790556040519081527fede4aee4284b8033b84c1aadcc51b229a4e46e6b42ab40092e237f07508b462690602090a1565b61ffff81169061271082116200063c576003805461ffff60981b191660989290921b61ffff60981b169190911790556040519081527f2e38c85b973ddf3d7c0cbd813bddb9b63db96d86ff7b6ccce361777d674d813c90602090a1565b6001600160601b031680156200063c57600380546001600160601b031916821790556040519081527f988fd919afedb9b211cf201222b0091d485871857d14d2a87946e1ee390a17f490602090a1565b6001600160a01b031680156200063c57600580546001600160a01b031916821790556040519081527f2d5eba1cf3f9252b2aa813087328fc416c6c2ad0fb1417f9f5f78f08cb24cfdb90602090a1565b64ffffffffff811690600282106200063c576003805464ffffffffff60d01b191660d09290921b64ffffffffff60d01b169190911790556040519081527f32e1033127c5a25fa4a87832fb767338db2bca3d4eba8f34be6d5a8f71e9227590602090a1565b6001600160a01b031680156200063c57600680546001600160a01b031916821790556040519081527fa75f06c1fcb711f11e4fe2a1e8b84e798cce8ea1c6d6db252abe31ebd836e21f90602090a1565b6006805464ffffffffff60a01b191660a083901b64ffffffffff60a01b1617905560405164ffffffffff90911681527ff020ff23e722cd62b0e67a05c051cc3dc4b4d0c48e01de57a0571ad6a180c35d90602090a1565b6003805464ffffffffff60a81b1916600160a81b179081905560016000819052600860205291906000805160206200665a83398151915260018101546001600160601b039060a01c1662000a0157505060035460016000819052600860205260c882901c65ffffffffff0016605883901c67ffff0000000000001617176000805160206200665a8339815191525560a081901b6001600160a01b0319167fad67d757c34507f157cacfa2e3153e9f260a2244f30428821be7be64587ac56055505b7ffbe046f0ca401af45e57af7a8efd3840294bfc077bf062f4b9919e2c028e161c60405180620009fc81906001602060408401938281520152565b0390a1565b5460901c64ffffffffff1660016000526008602052906000805160206200665a83398151915290815490600182179362000a3f575b505055620009c1565b600192935064ffffffffff9060601c16420160401b171790388062000a3656fe6080604052600436101561001257600080fd5b60003560e01c806301ffc9a714610307578063197a3243146103025780631df47f80146102fd5780631fe543e3146102f857806320e67232146102f3578063248a9ca3146102ee57806327ab6b68146102e95780632f2ff15d146102e4578063311b8d5c146102df57806336566f06146102da57806336568abe146102d557806340e58ee5146102d05780634245d5f0146102cb578063472f5b06146102c65780635410d098146102c157806354854797146102bc578063553be400146102b757806358fc096f146102b25780635c975abb146102ad5780635cb6dfff146102a857806361510d31146102a3578063624ab3ac1461029e57806365294500146102995780636df1d48a14610294578063709563e21461028f5780637c8b287c1461028a5780637d33ca3f146102855780637d7c3c74146102805780638f1327c01461027b578063911c66b81461027657806391d148541461027157806398753c461461026c5780639f5cfe0314610267578063a217fddf14610262578063aa73b5ac1461025d578063b12957f614610258578063b2185bb114610253578063bbc492c01461024e578063bfbf228414610249578063c66944ba14610244578063ca232b091461023f578063cb5305f31461023a578063d0a2c33614610235578063d547741f14610230578063ea8a1af01461022b578063f7cb789a146102265763fa2f0a8d1461022157600080fd5b613405565b6133bf565b613307565b6132a7565b61314b565b612fff565b612846565b6127ae565b61271c565b6126a5565b6125d8565b61255b565b612511565b6124d7565b612491565b61244e565b6123cc565b612328565b6121ce565b611cf3565b611b32565b611a06565b61195c565b6118a6565b6117f0565b61173e565b6116ec565b611682565b611641565b6115fe565b61147e565b611372565b611320565b611273565b6111dc565b611083565b610f9b565b610e6d565b610dd7565b610c63565b610a5d565b6109df565b610927565b610638565b610469565b610405565b61033b565b7fffffffff0000000000000000000000000000000000000000000000000000000081160361033657565b600080fd5b346103365760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103365760207fffffffff000000000000000000000000000000000000000000000000000000006004356103998161030c565b167f7965db0b0000000000000000000000000000000000000000000000000000000081149081156103d0575b506040519015158152f35b7f01ffc9a700000000000000000000000000000000000000000000000000000000915014386103c5565b600091031261033657565b346103365760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657602064ffffffffff60035460d01c16604051908152f35b73ffffffffffffffffffffffffffffffffffffffff81160361033657565b346103365760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103365773ffffffffffffffffffffffffffffffffffffffff6004356104b98161044b565b6104c1613b17565b16801561051f576020817fc1b5345cce283376356748dc57f2dfa7120431d016fc7ca9ba641bc65f91411d927fffffffffffffffffffffffff00000000000000000000000000000000000000006004541617600455604051908152a1005b63aa7feadc6000526004601cfd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b67ffffffffffffffff811161057057604052565b61052d565b60e0810190811067ffffffffffffffff82111761057057604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761057057604052565b67ffffffffffffffff81116105705760051b60200190565b92916105f5826105d2565b916106036040519384610591565b829481845260208094019160051b810192831161033657905b8282106106295750505050565b8135815290830190830161061c565b346103365760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103365760043560243567ffffffffffffffff811161033657366023820112156103365761069b9036906024816004013591016105ea565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168033036108f057506106f86106f183600052600a602052604060002090565b5460ff1690565b6106fe57005b61073061072661071884600052600a602052604060002090565b5460081c64ffffffffff1690565b64ffffffffff1690565b90610745826000526008602052604060002090565b906002610753835460ff1690565b61075c8161207e565b14610764575b005b610777906107728484614963565b6137c3565b51928360016107918193600052600a602052604060002090565b01556003808301918254906107a5826136e7565b9260005b8381106108bc5750505061089d61076296610898610887610837600361081b6002996108156108b49a600161080e6108067fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6108ac9e01846137d0565b51809b613765565b0190615107565b90613551565b50015473ffffffffffffffffffffffffffffffffffffffff1690565b61088060018a0191829073ffffffffffffffffffffffffffffffffffffffff167fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055565b5460a01c90565b6bffffffffffffffffffffffff1690565b613ac4565b845460301c61ffff1690613ac4565b612710900490565b910155614a7f565b806108df610726846108cf87958b613551565b50015460a81c64ffffffffff1690565b6108e982886137d0565b52016107a9565b604490604051907f1cf993f40000000000000000000000000000000000000000000000000000000082523360048301526024820152fd5b346103365760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103365761095e613b17565b7f67aa0e8084cf2c79566eed90861fb37a9bf4106afb0fd2ee5b3428b4a5767c7b60206003548060f81c15907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fff000000000000000000000000000000000000000000000000000000000000008360f81b16911617600355604051908152a1005b346103365760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103365760043560005260006020526020600160406000200154604051908152f35b9181601f840112156103365782359167ffffffffffffffff8311610336576020808501948460051b01011161033657565b34610336576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103365760043567ffffffffffffffff811161033657610aad903690600401610a2c565b90600192600260015414610c39576002600155610ac8613b5e565b610ad0613446565b600091610adc85613b79565b60005b858110610b9d5750507f573056d40bdb0e131a339ac518c08135633a29c4a83b7efb171c4f931fbf40d59450602081015180610b6e575b505080610b3b575b50610b2f60405192839233846136ba565b0390a161076260018055565b610b68905a90337f0000000000000000000000000000000000000000000000000000000000000000613f36565b38610b1e565b610b8f610b96925173ffffffffffffffffffffffffffffffffffffffff1690565b3390613e3c565b3880610b16565b80610baa8892888861349f565b610bd5610bc282356000526008602052604060002090565b91610bcc83613b8e565b858101906134e4565b610bde81613b79565b6003600093015b818410610bf6575050505001610adf565b90919297610c2f869189610c20610c0e8d888a613541565b35610c1a875482613bf4565b86613551565b50610c2a81613c0a565b613c3a565b9801929190610be5565b60046040517f1bbee726000000000000000000000000000000000000000000000000000000008152fd5b346103365760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657600435602435610ca18161044b565b60009180835282602052610cbb600160408520015461406c565b8083528260205260ff610cf183604086209073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b541615610cfc578280f35b80835282602052610d3082604085209073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b60017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082541617905573ffffffffffffffffffffffffffffffffffffffff339216907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d8480a438808280f35b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60209101126103365760043561ffff811681036103365790565b3461033657610de536610d9c565b610ded613b17565b61ffff8116906109c4821161051f577fede4aee4284b8033b84c1aadcc51b229a4e46e6b42ab40092e237f07508b4626916020917fffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffff72ffff00000000000000000000000000000000006003549260881b16911617600355604051908152a1005b346103365760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657610ea4613b17565b60025460ff811615610f3e575060025460ff811615610f14577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166002557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6020604051338152a16107626141ea565b60046040517f6cd60201000000000000000000000000000000000000000000000000000000008152fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00600191610f6a6143ee565b16176002557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a1005b346103365760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657602435610fd68161044b565b3373ffffffffffffffffffffffffffffffffffffffff821603610fff5761076290600435614286565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c6600000000000000000000000000000000006064820152fd5b34610336576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657600435906110bf613b17565b81156111905764ffffffffff60035460a81c169060005b83811061114a576107627fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85857f0c4874e1a947afdb9c813baf258eec6a442b25531183f82046efc9760f6407736040518061114085858360209093929193604081019481520152565b0390a10101614a7f565b8060019184016000526008835261118a604060002060047fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b016110d6565b63cbc4e0606000526004601cfd5b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60209101126103365760043564ffffffffff811681036103365790565b34610336576111ea3661119e565b6111f2613b17565b64ffffffffff811690610e10821161051f577fbdeccc4cf4c928bfff2005eee2fd4b91bb3d22035af62a93e35b1eedf853e3a3916020917fffffffffffffffffffffffffffffff0000000000ffffffffffffffffffffffff70ffffffffff0000000000000000000000006003549260601b16911617600355604051908152a1005b346103365760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610336576004356bffffffffffffffffffffffff8116809103610336576112c3613b17565b801561051f576020817f988fd919afedb9b211cf201222b0091d485871857d14d2a87946e1ee390a17f4927fffffffffffffffffffffffffffffffffffffffff0000000000000000000000006003541617600355604051908152a1005b346103365760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657602073ffffffffffffffffffffffffffffffffffffffff60065416604051908152f35b346103365760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610336576004356113ad8161044b565b6113b5613b17565b6002549073ffffffffffffffffffffffffffffffffffffffff8260081c1661141e5774ffffffffffffffffffffffffffffffffffffffff007fffffffffffffffffffffff0000000000000000000000000000000000000000ff9160081b16911617600255600080f35b63d6336f0d6000526004601cfd5b9060407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc83011261033657600435916024359067ffffffffffffffff82116103365761147a91600401610a2c565b9091565b6114873661142c565b600192919290600260015414610c395760026001556114a46143ee565b80156115f9576114be836000526008602052604060002090565b936114c885614424565b6114d18561446c565b60006114dc836136e7565b9360005b84811061156a5750503403611565576115227fa315167fc4200676e8597c5df065fafa8cecfeac15a8e2aded299a649e4a5175936040519384938733866137e4565b0390a1611547825464ffffffffff90600385015491808260081c169160901c1661472d565b611555575b61076260018055565b61155e91614764565b388061154c565b61051f565b80870190611582826000526008602052604060002090565b916115936108878585015460a01c90565b9081156115e8575b6115a584826145b3565b6115b0838989613541565b35906115bc8383613765565b61156557816115d6936115d09288976146a5565b956137b6565b936115e182896137d0565b52016114e0565b90506115f3816144cf565b9061159b565b614362565b346103365760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657602061ffff60035460981c16604051908152f35b346103365760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657602060ff600254166040519015158152f35b346103365760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657600435600052600a602052606060406000206001815491015464ffffffffff6040519260ff81161515845260081c1660208301526040820152f35b346103365760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657602073ffffffffffffffffffffffffffffffffffffffff60055416604051908152f35b34610336576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126117ed57600260015414610c39576002600155611785613b5e565b64ffffffffff8060035460a81c1690818352600860205260408320906117aa82613bb2565b6117b981835460681c16613858565b1642106117e057906117ce816117d3936149c0565b614a7f565b506117dd60018055565b80f35b63f4c0ca6e83526004601cfd5b80fd5b346103365760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103365773ffffffffffffffffffffffffffffffffffffffff6004356118408161044b565b611848613b17565b16801561051f576020817f2d5eba1cf3f9252b2aa813087328fc416c6c2ad0fb1417f9f5f78f08cb24cfdb927fffffffffffffffffffffffff00000000000000000000000000000000000000006005541617600555604051908152a1005b346103365760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103365773ffffffffffffffffffffffffffffffffffffffff6004356118f68161044b565b6118fe613b17565b16801561051f576020817fa75f06c1fcb711f11e4fe2a1e8b84e798cce8ea1c6d6db252abe31ebd836e21f927fffffffffffffffffffffffff00000000000000000000000000000000000000006006541617600655604051908152a1005b346103365760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657602064ffffffffff60065460a01c16604051908152f35b8015150361033657565b60407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc820112610336576004359067ffffffffffffffff8211610336576119f591600401610a2c565b9091602435611a03816119a2565b90565b3461033657611a14366119ac565b60009291839284915b808310611a6d57505050600014611a4f5750611a3b611a4b91614ba6565b6040519081529081906020820190565b0390f35b80821015611a63575050611a4b6000611a3b565b611a4b9103611a3b565b909194611a7b86838561349f565b611aa7611a9382356000526008602052604060002090565b91611a9d83613bc8565b60208101906134e4565b600383019081549160005b828110611ad85750505050506001916002611acf920154906137b6565b95019190611a1d565b611ae3818487613541565b3584811015611b2d57611af69083613551565b50805460ff16611b058161209a565b15611b14575b50600101611ab2565b6001919b6002611b26920154906137b6565b9a90611b0b565b613bfc565b611b3b366119ac565b91600292600193600260015414610c39576002600155611b59613b5e565b611b61613446565b91600095869282611b7188613b79565b611ce8575b875b878110611c515750505081611bcf575b5050928360207ffbb3d671e318a7ebc6333ba95648c22dc746b01f141b5e81939d55d4664be29595015180610b6e57505080610b3b5750610b2f60405192839233846136ba565b15611c085790611c007ffbb3d671e318a7ebc6333ba95648c22dc746b01f141b5e81939d55d4664be2959592614caa565b909338611b88565b80611c15611c1c92614c32565b349061389d565b848111611c4c577ffbb3d671e318a7ebc6333ba95648c22dc746b01f141b5e81939d55d4664be295940390611c00565b614370565b611c5c81898961349f565b611c87611c7482356000526008602052604060002090565b91611c7e83613bc8565b611a9d83614c02565b90611c9182613b79565b600091600384015b818410611cbf5750505050906000611cb784869401978854906137b6565b965501611b78565b9091929c611cde88918f611cd8610c0e8f92888a613541565b50613c3a565b9d01929190611c99565b3415611b765761051f565b346103365760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657600480359060243567ffffffffffffffff811161033657611d47903690600401610a2c565b9160443590611d55826119a2565b6002916001600260015414610c39576002600155611d716143ee565b6000938493611d7f88613b79565b855b888110611ed6575050505081611ea5575b5050611da8846000526008602052604060002090565b611db181614424565b611dbb81866145b3565b611dc48161446c565b611dd5610887600183015460a01c90565b94611de08684613765565b80611e66575b5085831061156557611e1e610b2f937fecd5c5544dcd4a5344389c360ff979c215f25290177e786ca2c407e58a95b88a9783856146a5565b9181611e42825464ffffffffff90600385015491808260081c169160901c1661472d565b611e56575b505060405194859433866138aa565b611e5f91614764565b3881611e47565b9283611e9f91611e74613b5e565b03935a90337f0000000000000000000000000000000000000000000000000000000000000000613f36565b38611de6565b15611eba57611eb390614caa565b3880611d92565b908181106000036143705781611ed1910391614c32565b611eb3565b611ee1818a8a61349f565b611ef681356000526008602052604060002090565b90611f02825460ff1690565b91611f0c8361207e565b60039182841061204a57611f3890611f238561207e565b838514612029575b60208195939501906134e4565b9092611f4382613b79565b806000950192878114935b838710611f6357505050505050508301611d81565b9091929394959c611f8a611f788f878a613541565b35611f84845482613bf4565b83613551565b50611f9481614dd5565b805460ff16611fa28161209a565b612024578b918b6120099289611fb78861207e565b612016575b612001888201740100000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff825416179055565b0154906137b6565b9d01959493929190611f4e565b61201f81613c0a565b611fbc565b61437e565b61203283614c02565b60006120438985019c8d54906137b6565b9b55611f2b565b613ba4565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6005111561208857565b61204f565b9060058210156120885752565b6003111561208857565b969893959097949291926020610160610140996120c4818c81019d61208d565b829a64ffffffffff8098168483015261ffff6040971660408301528760609b166060830152876080951660808301528760a0961660a083015260c09873ffffffffffffffffffffffffffffffffffffffff9e8f1660c08401526bffffffffffffffffffffffff60e09b1660e08401526101008301526101208201528d51809c52019b01996000975b8a89106121625750505050505050505050505090565b909192939495969798999a9b8a896001928f8b8b915180516121838161209a565b8452808601518916868501528b8101518c85015287810151888501528981015189168a8501528a81015115158b8501520151168b820152019d019b9a9901979695949392919061214c565b346103365760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103365760043560008181526008602052604090208054603081901c61ffff16929091611a4b9190612233905460401c64ffffffffff1690565b9061225961224b826000526008602052604060002090565b5460681c64ffffffffff1690565b61227e612270836000526008602052604060002090565b5460901c64ffffffffff1690565b6122b26001612297856000526008602052604060002090565b015473ffffffffffffffffffffffffffffffffffffffff1690565b906122d460016122cc866000526008602052604060002090565b015460a01c90565b9261230c600361230660026122f3896000526008602052604060002090565b0154976000526008602052604060002090565b016138e9565b95604051998960ff64ffffffffff8d9c60081c1691168b6120a4565b34610336576123363661119e565b61233e613b17565b64ffffffffff8116906002821061051f577f32e1033127c5a25fa4a87832fb767338db2bca3d4eba8f34be6d5a8f71e92275916020917fff0000000000ffffffffffffffffffffffffffffffffffffffffffffffffffff7effffffffff00000000000000000000000000000000000000000000000000006003549260d01b16911617600355604051908152a1005b346103365760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657602060ff61244260243561240e8161044b565b6004356000526000845260406000209073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b54166040519015158152f35b346103365760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657602061ffff60035460881c16604051908152f35b346103365760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657602064ffffffffff60035460a81c16604051908152f35b346103365760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657602060405160008152f35b346103365760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103365760206bffffffffffffffffffffffff60035416604051908152f35b346103365760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103365760206125cf60243561259b8161044b565b6004356000526009835260406000209073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b54604051908152f35b34610336576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126117ed57600260015414610c3957600260015561261f6143ee565b64ffffffffff8060035460a81c168083526008602052604083209161264383613bde565b825490808260901c16916126686126646003870154848460081c168661472d565b1590565b612682575b50505061267991614764565b6117dd60018055565b60401c1642106126a05760021161269b5738808061266d565b61439a565b61438c565b346103365760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103365773ffffffffffffffffffffffffffffffffffffffff6004356126f58161044b565b16600052600b60205260406000206024356000526020526020604060002054604051908152f35b34610336577ff020ff23e722cd62b0e67a05c051cc3dc4b4d0c48e01de57a0571ad6a180c35d602061274d3661119e565b612755613b17565b6006547fffffffffffffff0000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000008360a01b1691161760065564ffffffffff60405191168152a1005b34610336576127bc36610d9c565b6127c4613b17565b61ffff811690612710821161051f577f2e38c85b973ddf3d7c0cbd813bddb9b63db96d86ff7b6ccce361777d674d813c916020917fffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffff74ffff000000000000000000000000000000000000006003549260981b16911617600355604051908152a1005b61284f3661142c565b91600260015414610c395760026001556128676143ee565b61287b816000526008602052604060002090565b61288481614424565b61288e81836145b3565b6128978161446c565b60038101549360009081946128be6128b9866000526008602052604060002090565b6137a3565b9234612f6b5782156115f9575b82612956575b505050612920857f73a19dd210f1a7f902193214c0ee91dd35ee5b4d920cba8d519eca65a7b488ca96859355835464ffffffffff808260901c169161291683856152f6565b60081c169061472d565b612946575b50506040805133815260208101929092528101919091528060608101610b2f565b61294f91614764565b3881612925565b919061296182614df3565b926000905b838210612a51575050505073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016803b15610336576129f16000929183926040519485809481937f0ca8e8a80000000000000000000000000000000000000000000000000000000083523090339060048501614f0c565b03925af1958615612a4c57808593612920937f73a19dd210f1a7f902193214c0ee91dd35ee5b4d920cba8d519eca65a7b488ca99612a33575b509350966128d1565b80612a40612a469261055c565b806103fa565b38612a2a565b613af0565b93979298612a64828b859a949995614e8e565b94612a7160208701613a06565b946001612ad5612a8089614ece565b604051612ac281612a9660208201948d86613a10565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282610591565b5190206000526007602052604060002090565b5403612f6657612b1884612b098873ffffffffffffffffffffffffffffffffffffffff16600052600b602052604060002090565b90600052602052604060002090565b546002612b2489614ece565b612b2d8161209a565b03612d11578015612ccd575b612b5a90612b546108876001899e959798969e015460a01c90565b90613b0d565b93612b6485615399565b612b7b612b7460408a018a6134e4565b90506136e7565b9a6000945b612b8d60408b018b6134e4565b9050861015612c39578c83808d898b98968f9a988e612bad8c859a6137b6565b9b612bb7936153ae565b9960408101612bc5916134e4565b612bcf9291613541565b3591612be59160005260206000209060021b0190565b3379ffffffffff00000000000000000000000000000000000000000060a88b901b16176003820155600260088e901b1781556001015560010196612c28916137d0565b600190526001019491939092612b80565b9c98612cb2929e965060019550612c79612c9a92989c959d9499612c5d878d6137d0565b519073ffffffffffffffffffffffffffffffffffffffff169052565b612c906020612c88878d6137d0565b510160019052565b60408101906134e4565b91906040612ca8868c6137d0565b51019236916105ea565b90526060612cc083896137d0565b5101525b01909291612966565b50612b5a612cda8861544c565b80612d0987612b098b73ffffffffffffffffffffffffffffffffffffffff16600052600b602052604060002090565b559050612b39565b6001612d278994979b959e969c98939d99614ece565b612d308161209a565b14612d41575b505050600190612cc4565b919a829c939c95919515612f25575b612d67612d6060408e018e6134e4565b36916105ea565b6001815103612f2057612d7c612d84916137c3565b518094613ac4565b6040517f313ce56700000000000000000000000000000000000000000000000000000000815260208160048173ffffffffffffffffffffffffffffffffffffffff8c165afa8015612a4c576108876001612df38f9495612b54612b5495612dfc98600091612ef1575b50613afc565b93015460a01c90565b9b612e068d615399565b60608101358d10612eec5784918d8f8b8e948b612e2384846137d0565b5173ffffffffffffffffffffffffffffffffffffffff9091169052612e4883836137d0565b516020016000905260408101612e5d916134e4565b92612e6891926137d0565b51606001913690612e78926105ea565b9052612e83916137b6565b9c612e8d936153ae565b93612ea3838960005260206000209060021b0190565b3379ffffffffff00000000000000000000000000000000000000000060a888901b16176003820155916002830155612ee0919060081b6001179055565b60010198388080612d36565b6143a8565b612f13915060203d602011612f19575b612f0b8183610591565b810190613ad7565b38612ded565b503d612f01565b613b80565b9150612f3085615082565b9182612f608c612b098973ffffffffffffffffffffffffffffffffffffffff16600052600b602052604060002090565b55612d50565b615074565b509450612f7f610887600185015460a01c90565b612f898134613765565b61156557612f979034613b0d565b946001612fa587898761532d565b97612fee612fbe828760005260206000209060021b0190565b3379ffffffffff00000000000000000000000000000000000000000060a88d901b16176003820155349060020155565b01966128cb565b6003111561033657565b346103365760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103365760043567ffffffffffffffff81116103365761304e903690600401610a2c565b6024359161305b83612ff5565b60443592613068846119a2565b61307061502d565b6130798161209a565b8015612f665760005b8381106130c157507f14f4f9b9a2d50cb168899c4825e24b7ffdc472b1dca88ddad74a834f7b62470b936130bc9160405194859485613a51565b0390a1005b600190600086156131465750815b61313f6130e56130e0848989613541565b613a06565b60ff6040519361312a856130fe8a602083019687613a10565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101875286610591565b16925190206000526007602052604060002090565b5501613082565b6130cf565b34610336577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60408136011261033657600435906024359067ffffffffffffffff82116103365760a09082360301126103365773ffffffffffffffffffffffffffffffffffffffff91602061321e6131c560248501613a06565b936131f484612b098773ffffffffffffffffffffffffffffffffffffffff16600052600b602052604060002090565b5490811561328d575b6132118160446132179301906004016134e4565b90613538565b3590613ac4565b926004604051809681937f313ce567000000000000000000000000000000000000000000000000000000008352165afa928315612a4c5761088760016122cc61327c611a3b96612b54611a4b99612b5497600091612ef15750613afc565b946000526008602052604060002090565b905061321761321161329e87615082565b929150506131fd565b346103365760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610336576107626024356004356132e88261044b565b80600052600060205261330260016040600020015461406c565b614286565b34610336576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126117ed57600260015414610c3957600260015561334e613b5e565b64ffffffffff8060035460a81c168083526008602052604083209161337283613bde565b8254818160401c1680159081156133b5575b506133a8579060019160901c16116133a3576117ce816117d3936149c0565b6143b6565b63f9ad93f585526004601cfd5b9050421038613384565b346103365760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657602064ffffffffff60035460601c16604051908152f35b346103365760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657602060035460f81c6040519015158152f35b604051906040820182811067ffffffffffffffff8211176105705760405260006020838281520152565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b91908110156134df5760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc181360301821215610336570190565b613470565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610336570180359067ffffffffffffffff821161033657602001918160051b3603831361033657565b90156134df5790565b91908110156134df5760051b0190565b80548210156134df5760005260206000209060021b0190600090565b90918281527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83116103365760209260051b809284830137010190565b908290808452602080940193600592818360051b82010195856000925b8584106135d957505050505050505090565b90919293949596977fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082820301845288357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc18436030181121561033657830160409080358352878101357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18236030181121561033657019087823592019267ffffffffffffffff831161033657828b1b3603841361033657600193899383838695866136a8960152019161356d565b9a0194019401929695949391906135c7565b60409073ffffffffffffffffffffffffffffffffffffffff611a03959316815281602082015201916135aa565b906136f1826105d2565b6136fe6040519182610591565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061372c82946105d2565b0190602036910137565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b811561376f570690565b613736565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b90600382018092116137b157565b613774565b919082018092116137b157565b8051156134df5760200190565b80518210156134df5760209160051b010190565b92909373ffffffffffffffffffffffffffffffffffffffff61381d9395168452602094602085015260806040850152608084019161356d565b9060608183039101526020808451928381520193019160005b828110613844575050505090565b835185529381019392810192600101613836565b9062015f9064ffffffffff809316019182116137b157565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82019182116137b157565b919082039182116137b157565b9160609373ffffffffffffffffffffffffffffffffffffffff6138df93989796981684526080602085015260808401916135aa565b9460408201520152565b9081546138f5816105d2565b926040936139066040519182610591565b82815280946020809201926000526020600020906000935b85851061392d57505050505050565b600484600192845161393e81610575565b6139f864ffffffffff88546139e460ff80831661395a8161209a565b865261399873ffffffffffffffffffffffffffffffffffffffff809460081c168988019073ffffffffffffffffffffffffffffffffffffffff169052565b898c01548b87015260028c015460608701526139d460038d0154938416608088019073ffffffffffffffffffffffffffffffffffffffff169052565b60a083811c909116151590860152565b60a81c1660c083019064ffffffffff169052565b81520193019401939161391e565b35611a038161044b565b90917fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060159360601b168252613a458161209a565b60f81b60148201520190565b929493918060608501606086525260808401919060005b818110613a8c575050509060409194613a808161209a565b60208401521515910152565b90919260019073ffffffffffffffffffffffffffffffffffffffff8535613ab28161044b565b16815260209081019401929101613a68565b818102929181159184041417156137b157565b90816020910312610336575160ff811681036103365790565b6040513d6000823e3d90fd5b60ff16604d81116137b157600a0a90565b811561376f570490565b3360009081527fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5602052604090205460ff1615613b5057565b6330cd74716000526004601cfd5b60035460f81c15613b6b57565b63010a265a6000526004601cfd5b15613b8057565b63947d5a846000526004601cfd5b5460ff16600581101561208857600403613ba457565b63f525e3206000526004601cfd5b5460ff16600581101561208857600203613ba457565b5460ff16600581101561208857600303613ba457565b5460ff16600581101561208857600103613ba457565b1015613bfc57565b6363df81716000526004601cfd5b6003015473ffffffffffffffffffffffffffffffffffffffff163303613c2c57565b633cc50b456000526004601cfd5b90613c4482614dd5565b613c8a60038301740100000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff825416179055565b815460ff8116613c998161209a565b80613cae5750505060020154611a03916137b6565b613cba8194939461209a565b60028103613cf45750508054611a03925060019060081c73ffffffffffffffffffffffffffffffffffffffff1691015490339030906151a6565b80613d0060019261209a565b14613d0c575b50505090565b73ffffffffffffffffffffffffffffffffffffffff809160081c16613d45845173ffffffffffffffffffffffffffffffffffffffff1690565b9182168103613d6f57505060206002613d6492015492019182516137b6565b90525b388080613d06565b613da29084602060029594960195865180613dab575b50509073ffffffffffffffffffffffffffffffffffffffff169052565b01549052613d67565b613db6913390613e3c565b3880613d85565b67ffffffffffffffff811161057057601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b3d15613e22573d90613e0882613dbd565b91613e166040519384610591565b82523d6000602084013e565b606090565b908160209103126103365751611a03816119a2565b919091803b15613f0c576040517fa9059cbb000000000000000000000000000000000000000000000000000000006020820190815273ffffffffffffffffffffffffffffffffffffffff9094166024820152604481019290925260009283928390613eaa8160648101612a96565b51925af1613eb6613df7565b9015613ee257805180613ec7575050565b8160208061266493613edc9501019101613e27565b613ee257565b60046040517ff1568f95000000000000000000000000000000000000000000000000000000008152fd5b60046040517f09ee12d5000000000000000000000000000000000000000000000000000000008152fd5b613f4b82849395600080809781948294f11590565b613f56575b50505050565b73ffffffffffffffffffffffffffffffffffffffff16803b1561406857604051937fd0e30db0000000000000000000000000000000000000000000000000000000008552838560048186865af1938415612a4c5761400f95602095614055575b506040518096819582947fa9059cbb000000000000000000000000000000000000000000000000000000008452600484016020909392919373ffffffffffffffffffffffffffffffffffffffff60408201951681520152565b03925af18015612a4c57614026575b808080613f50565b6140479060203d60201161404e575b61403f8183610591565b810190613e27565b503861401e565b503d614035565b80612a406140629261055c565b38613fb6565b8280fd5b80600052600060205260ff6140a53360406000209073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b5416156140af5750565b33906140b96156cb565b9160306140c5846137c3565b5360786140d1846156f8565b5360295b6001811161419c5761419861413d61416686612a966140fd886140f88915615744565b6157a9565b614137604051958694614137602087016017907f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081520190565b9061528b565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000815260110190565b6040519182917f08c379a0000000000000000000000000000000000000000000000000000000008352600483016152e5565b0390fd5b90600f81169060108210156134df577f30313233343536373839616263646566000000000000000000000000000000006141e5921a6141db8487615708565b5360041c91615719565b6140d5565b64ffffffffff60035460a81c166000805b6001811061424157505061423e907f0c4874e1a947afdb9c813baf258eec6a442b25531183f82046efc9760f6407736040805183815260016020820152a1614a7f565b50565b806001918401835260086020526142806040842060047fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b016141fb565b6000908082528160205260ff6142bf84604085209073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b54166142ca57505050565b808252816020526142fe83604084209073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0081541690557ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b73ffffffffffffffffffffffffffffffffffffffff3394169280a4565b63a95231d56000526004601cfd5b630134f2786000526004601cfd5b63a1e9dd9d6000526004601cfd5b63f9ad93f56000526004601cfd5b637e439aed6000526004601cfd5b63f48cb8a06000526004601cfd5b637cd9dd6a6000526004601cfd5b63f90121326000526004601cfd5b63c11f59766000526004601cfd5b630da5618b6000526004601cfd5b60ff600254166143fa57565b60046040517f1309a563000000000000000000000000000000000000000000000000000000008152fd5b5460ff811660058110156120885760011490811591614445575b50613ba457565b60401c64ffffffffff16801515915081614461575b503861443e565b90504210153861445a565b805464ffffffffff808260401c161561448457505050565b60035460601c1642018042116137b1576cffffffffff00000000000000007fffffffffffffffffffffffffffffffffffffff0000000000ffffffffffffffff9160401b169116179055565b9060035460017fffffffffffffffffffffffff00000000000000000000000000000000000000006145196bffffffffffffffffffffffff8416956000526008602052604060002090565b9267ffff0000000000008160581c1665ffffffffff008260c81c1617845560a01b16910155565b9060035460017fffffffffffffffffffffffff000000000000000000000000000000000000000061458a6bffffffffffffffffffffffff8416956000526008602052604060002090565b928267ffff0000000000008260581c1665ffffffffff008360c81c161717845560a01b16910155565b8060005260096020526145e960406000203373ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b54908115614630575b6001925060005260096020520161462d3360406000209073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b55565b82549264ffffffffff93848160901c16948160081c168514614697577fffffffffffffffffff0000000000ffffffffffffffffffffffffffffffffffff16600194850160901b76ffffffffff000000000000000000000000000000000000161790556145f2565b63b53a57db6000526004601cfd5b9091939293801561376f5784049360038201549160018301936146f36146e2888664ffffffffff956146dd87825460901c168b6152f6565b61532d565b916000526008602052604060002090565b93600385018095116137b15760029261471a614728928760005260206000209060021b0190565b921660a81b33176003830155565b015555565b919082109182159261473e57505090565b60011091508161474c575090565b60649150101590565b90816020910312610336575190565b6147b3906147728382614a22565b80547fffffffffffffffffffffffffffff0000000000ffffffffffffffffffffffffff164260681b71ffffffffff0000000000000000000000000016179055565b6040517f5d3b1d300000000000000000000000000000000000000000000000000000000081527f000000000000000000000000000000000000000000000000000000000000000060048201527f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1660248201527f000000000000000000000000000000000000000000000000000000000000000061ffff1660448201526207a12060648201526001608482015260208160a48160007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff165af1908115612a4c57600091614934575b506148d16106f182600052600a602052604060002090565b61492f577f3d94fecedaa4f90b8bd459797adb95f5bb11426025c5541390d9ccc1ad1b60a19181600052600a60205260406000208160081b600117905561492a6040519283928360209093929193604081019481520152565b0390a1565b6143c4565b614956915060203d60201161495c575b61494e8183610591565b810190614755565b386148b9565b503d614944565b7ffbe046f0ca401af45e57af7a8efd3840294bfc077bf062f4b9919e2c028e161c9160409160037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055815190815260036020820152a1565b7ffbe046f0ca401af45e57af7a8efd3840294bfc077bf062f4b9919e2c028e161c91614a1360409260047fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b815190815260046020820152a1565b7ffbe046f0ca401af45e57af7a8efd3840294bfc077bf062f4b9919e2c028e161c9160409160027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055815190815260026020820152a1565b600101906003547fffffffffffff0000000000ffffffffffffffffffffffffffffffffffffffffff79ffffffffff0000000000000000000000000000000000000000008460a81b1691161780600355614ae2836000526008602052604060002090565b6bffffffffffffffffffffffff614afd600183015460a01c90565b16614b48575050614b0d82614540565b505b60408051838152600160208201527ffbe046f0ca401af45e57af7a8efd3840294bfc077bf062f4b9919e2c028e161c918190810161492a565b54614b5c9060901c64ffffffffff16610726565b90614b71846000526008602052604060002090565b908154906001821793614b87575b505055614b0f565b600192935064ffffffffff9060601c16420160401b1717903880614b7f565b670de0b6b3a764000090808202918204036137b157614bcf9061ffff60035460981c1690613ac4565b614bf373ffffffffffffffffffffffffffffffffffffffff60025460081c16615082565b801561376f5761271091040490565b6001015473ffffffffffffffffffffffffffffffffffffffff163303614c2457565b63618c72426000526004601cfd5b60407fa0c67dacab0c86ad0a872c2ed3fa9deb08f80f4f0543d481f2fac9ee41d0269191614c9b73ffffffffffffffffffffffffffffffffffffffff60045416825a917f0000000000000000000000000000000000000000000000000000000000000000613f36565b815190815260006020820152a1565b614cb390614ba6565b73ffffffffffffffffffffffffffffffffffffffff90817f000000000000000000000000000000000000000000000000000000000000000016918060025460081c169060045416833b156103365760846000928360405196879485937fda3e8ce4000000000000000000000000000000000000000000000000000000008552600485015233602485015260448401528660648401525af1918215612a4c577fa0c67dacab0c86ad0a872c2ed3fa9deb08f80f4f0543d481f2fac9ee41d0269192614dc2575b5060025460081c73ffffffffffffffffffffffffffffffffffffffff166040805192835273ffffffffffffffffffffffffffffffffffffffff90911660208301528190810161492a565b80612a40614dcf9261055c565b38614d78565b6003015460a01c60ff16614de557565b636507689f6000526004601cfd5b90614dfd826105d2565b604090614e0d6040519182610591565b8381527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0614e3b82956105d2565b01906000805b838110614e4f575050505050565b845190608082019180831067ffffffffffffffff8411176105705760209287528381528284818301526060808984015280830152828601015201614e41565b91908110156134df5760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6181360301821215610336570190565b35611a0381612ff5565b90815180825260208080930193019160005b828110614ef8575050505090565b835185529381019392810192600101614eea565b93919392909260609460608201606083528551809152608090608084019760808260051b860101986020809901936000925b848410614f925750505050505090614f74604092614f90959683019073ffffffffffffffffffffffffffffffffffffffff169052565b019073ffffffffffffffffffffffffffffffffffffffff169052565b565b90919293949a8a8061501d838f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff808d60019703018952519073ffffffffffffffffffffffffffffffffffffffff825116815283820151614ff18161209a565b848201528661500d60408a81860151918501528a840190614ed8565b9201519087818403910152614ed8565b9d01940194019294939190614f3e565b3360009081527fee57cd81e84075558e8fcc182a1f4393f91fc97f963a136e66b7f949a62f319f602052604090205460ff161561506657565b637c214f046000526004601cfd5b63c1ab6dc16000526004601cfd5b602073ffffffffffffffffffffffffffffffffffffffff604481600554169360405194859384927fe3cae776000000000000000000000000000000000000000000000000000000008452166004830152610e1060248301525afa908115612a4c576000916150ee575090565b611a03915060203d60201161495c5761494e8183610591565b805191821561519e576000925b80841061517057508215159182615152575b505015611a03577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b61516791925061516184613870565b906137d0565b51143880615126565b61517a81856156b6565b908261518683866137d0565b5111156151935750615114565b935060010192615114565b505050600090565b909192813b15613f0c576040519260208401947f23b872dd00000000000000000000000000000000000000000000000000000000865273ffffffffffffffffffffffffffffffffffffffff809216602486015216604484015260648301526064825260a082019282841067ffffffffffffffff851117610570576000809493819460405251925af1615236613df7565b501561523e57565b60046040517fe0f5c508000000000000000000000000000000000000000000000000000000008152fd5b60005b83811061527b5750506000910152565b818101518382015260200161526b565b9061529e60209282815194859201615268565b0190565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6020936152de81518092818752878088019101615268565b0116010190565b906020611a039281815201906152a2565b6064811161531f576064146153085750565b60011461531157565b63ae24220e6000526004601cfd5b6327e6fcc76000526004601cfd5b919061533882615399565b8061534a575064ffffffffff91501690565b600392837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61537b93019101613551565b5064ffffffffff928391015460a81c169081018091116137b1571690565b156153a057565b63f91214386000526004601cfd5b64ffffffffff939084169283156153ce5750508216019081116137b15790565b90919250611a03935061532d565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610336570180359067ffffffffffffffff82116103365760200191813603831361033657565b919082604091031261033657602082356154468161044b565b92013590565b9060808201357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8183360301811215610336578201916020809101356154908161044b565b604084013593428511801561568e575b61568957604051918261550f8582019283608060009193929373ffffffffffffffffffffffffffffffffffffffff60a08201957f60d14eec5d309c7bcbba8f8779f8070820b882731ce8afd4d9282a327dfe6ede835260016020840152610e1060408401521660608201520152565b03926155417fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe094858101835282610591565b51902090803582036156845761566f8461563161563d6156749673ffffffffffffffffffffffffffffffffffffffff9a61567c998701976155f461558f6155888b8b6153dc565b3691615846565b878151910120926155e86040519384928a8401964692889094939260809260a08301967f8c01f2233cc36f533c3fbfd8037c653a0326c46e0dc25bff9aea020c1a72a05484526020840152604083015260608201520152565b03848101835282610591565b5190209360405193849182019586603c917f19457468657265756d205369676e6564204d6573736167653a0a3332000000008252601c8201520190565b03908101835282610591565b51902060065473ffffffffffffffffffffffffffffffffffffffff1661566961558860608601866153dc565b916158a9565b6153dc565b81019061542d565b9216612f6657565b6143e0565b6143d2565b506156af6156a961072660065464ffffffffff9060a01c1690565b866137b6565b42116154a0565b90808216911860011c81018091116137b15790565b604051906060820182811067ffffffffffffffff82111761057057604052602a8252604082602036910137565b8051600110156134df5760210190565b9081518110156134df570160200190565b80156137b1577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b1561574b57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602060248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152fd5b604051906080820182811067ffffffffffffffff8211176105705760405260428252606036602084013760306157de836137c3565b5360786157ea836156f8565b536041905b6001821161580257611a03915015615744565b600f81169060108210156134df577f3031323334353637383961626364656600000000000000000000000000000000615840921a6141db8486615708565b906157ef565b92919261585282613dbd565b916158606040519384610591565b829481845281830111610336578281602093846000960137010152565b908160209103126103365751611a038161030c565b604090611a039392815281602082015201906152a2565b91813b615903576158ba91926159eb565b73ffffffffffffffffffffffffffffffffffffffff908116911614614f905760046040517fd1085d1b000000000000000000000000000000000000000000000000000000008152fd5b61595673ffffffffffffffffffffffffffffffffffffffff926020926040519485809481937f1626ba7e00000000000000000000000000000000000000000000000000000000998a845260048401615892565b0392165afa8015612a4c577fffffffff00000000000000000000000000000000000000000000000000000000916000916159bc575b501614614f905760046040517ff6cd0e2f000000000000000000000000000000000000000000000000000000008152fd5b6159de915060203d6020116159e4575b6159d68183610591565b81019061587d565b3861598b565b503d6159cc565b815160418103615b2e57506020820151916060604082015191015160001a925b7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08211615b045760ff8416601b8114159081615af8575b50615ac4576040805193845260ff9490941660208085019190915293830152606082015260008080529060809060015afa15612a4c576000519073ffffffffffffffffffffffffffffffffffffffff821615615a9a57565b60046040517ff05a20c7000000000000000000000000000000000000000000000000000000008152fd5b6040517f417893a400000000000000000000000000000000000000000000000000000000815260ff85166004820152602490fd5b601c9150141538615a42565b60046040517fc1851252000000000000000000000000000000000000000000000000000000008152fd5b60408103615b71575060406020830151920151601b7f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82169160ff1c0192615a0b565b6040517fd42b4bbd0000000000000000000000000000000000000000000000000000000081526004810191909152602490fdfea2646970667358221220119e9e5a46e5948caac21a0c13109c32fcd0da478b9c78f517652568b63f899d64736f6c634300081700332f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0dad67d757c34507f157cacfa2e3153e9f260a2244f30428821be7be64587ac55f0000000000000000000000003ab105f0e4a22ec4a96a9b0ca90c5c534d21f3a70000000000000000000000003ab105f0e4a22ec4a96a9b0ca90c5c534d21f3a700000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000e10000000000000000000000000000000000000000000000000002386f26fc10000000000000000000000000000b5a9e5a319c7fda551a30be592c77394bf935c6f00000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000013888af398995b04c28e9951adb9721ef74c74f93e6a478f39e7e0777be13527e7ef00000000000000000000000000000000000000000000000000000000000002de000000000000000000000000271682deb8c4e0901d1a1550ad2e64d568e69909000000000000000000000000aeb1d03929bf87f69888f381e73fbf75753d75af00000000000000000000000000000000000ea4af05656c17b90f4d64add29e1d00000000000000000000000000000000000a95dbfc66d37f3fc5e597c0b03daf000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000005a0000000000000000000000000000000000000000000000000000000000000003
Deployed Bytecode
0x6080604052600436101561001257600080fd5b60003560e01c806301ffc9a714610307578063197a3243146103025780631df47f80146102fd5780631fe543e3146102f857806320e67232146102f3578063248a9ca3146102ee57806327ab6b68146102e95780632f2ff15d146102e4578063311b8d5c146102df57806336566f06146102da57806336568abe146102d557806340e58ee5146102d05780634245d5f0146102cb578063472f5b06146102c65780635410d098146102c157806354854797146102bc578063553be400146102b757806358fc096f146102b25780635c975abb146102ad5780635cb6dfff146102a857806361510d31146102a3578063624ab3ac1461029e57806365294500146102995780636df1d48a14610294578063709563e21461028f5780637c8b287c1461028a5780637d33ca3f146102855780637d7c3c74146102805780638f1327c01461027b578063911c66b81461027657806391d148541461027157806398753c461461026c5780639f5cfe0314610267578063a217fddf14610262578063aa73b5ac1461025d578063b12957f614610258578063b2185bb114610253578063bbc492c01461024e578063bfbf228414610249578063c66944ba14610244578063ca232b091461023f578063cb5305f31461023a578063d0a2c33614610235578063d547741f14610230578063ea8a1af01461022b578063f7cb789a146102265763fa2f0a8d1461022157600080fd5b613405565b6133bf565b613307565b6132a7565b61314b565b612fff565b612846565b6127ae565b61271c565b6126a5565b6125d8565b61255b565b612511565b6124d7565b612491565b61244e565b6123cc565b612328565b6121ce565b611cf3565b611b32565b611a06565b61195c565b6118a6565b6117f0565b61173e565b6116ec565b611682565b611641565b6115fe565b61147e565b611372565b611320565b611273565b6111dc565b611083565b610f9b565b610e6d565b610dd7565b610c63565b610a5d565b6109df565b610927565b610638565b610469565b610405565b61033b565b7fffffffff0000000000000000000000000000000000000000000000000000000081160361033657565b600080fd5b346103365760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103365760207fffffffff000000000000000000000000000000000000000000000000000000006004356103998161030c565b167f7965db0b0000000000000000000000000000000000000000000000000000000081149081156103d0575b506040519015158152f35b7f01ffc9a700000000000000000000000000000000000000000000000000000000915014386103c5565b600091031261033657565b346103365760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657602064ffffffffff60035460d01c16604051908152f35b73ffffffffffffffffffffffffffffffffffffffff81160361033657565b346103365760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103365773ffffffffffffffffffffffffffffffffffffffff6004356104b98161044b565b6104c1613b17565b16801561051f576020817fc1b5345cce283376356748dc57f2dfa7120431d016fc7ca9ba641bc65f91411d927fffffffffffffffffffffffff00000000000000000000000000000000000000006004541617600455604051908152a1005b63aa7feadc6000526004601cfd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b67ffffffffffffffff811161057057604052565b61052d565b60e0810190811067ffffffffffffffff82111761057057604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761057057604052565b67ffffffffffffffff81116105705760051b60200190565b92916105f5826105d2565b916106036040519384610591565b829481845260208094019160051b810192831161033657905b8282106106295750505050565b8135815290830190830161061c565b346103365760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103365760043560243567ffffffffffffffff811161033657366023820112156103365761069b9036906024816004013591016105ea565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000271682deb8c4e0901d1a1550ad2e64d568e69909168033036108f057506106f86106f183600052600a602052604060002090565b5460ff1690565b6106fe57005b61073061072661071884600052600a602052604060002090565b5460081c64ffffffffff1690565b64ffffffffff1690565b90610745826000526008602052604060002090565b906002610753835460ff1690565b61075c8161207e565b14610764575b005b610777906107728484614963565b6137c3565b51928360016107918193600052600a602052604060002090565b01556003808301918254906107a5826136e7565b9260005b8381106108bc5750505061089d61076296610898610887610837600361081b6002996108156108b49a600161080e6108067fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6108ac9e01846137d0565b51809b613765565b0190615107565b90613551565b50015473ffffffffffffffffffffffffffffffffffffffff1690565b61088060018a0191829073ffffffffffffffffffffffffffffffffffffffff167fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055565b5460a01c90565b6bffffffffffffffffffffffff1690565b613ac4565b845460301c61ffff1690613ac4565b612710900490565b910155614a7f565b806108df610726846108cf87958b613551565b50015460a81c64ffffffffff1690565b6108e982886137d0565b52016107a9565b604490604051907f1cf993f40000000000000000000000000000000000000000000000000000000082523360048301526024820152fd5b346103365760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103365761095e613b17565b7f67aa0e8084cf2c79566eed90861fb37a9bf4106afb0fd2ee5b3428b4a5767c7b60206003548060f81c15907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fff000000000000000000000000000000000000000000000000000000000000008360f81b16911617600355604051908152a1005b346103365760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103365760043560005260006020526020600160406000200154604051908152f35b9181601f840112156103365782359167ffffffffffffffff8311610336576020808501948460051b01011161033657565b34610336576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103365760043567ffffffffffffffff811161033657610aad903690600401610a2c565b90600192600260015414610c39576002600155610ac8613b5e565b610ad0613446565b600091610adc85613b79565b60005b858110610b9d5750507f573056d40bdb0e131a339ac518c08135633a29c4a83b7efb171c4f931fbf40d59450602081015180610b6e575b505080610b3b575b50610b2f60405192839233846136ba565b0390a161076260018055565b610b68905a90337f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2613f36565b38610b1e565b610b8f610b96925173ffffffffffffffffffffffffffffffffffffffff1690565b3390613e3c565b3880610b16565b80610baa8892888861349f565b610bd5610bc282356000526008602052604060002090565b91610bcc83613b8e565b858101906134e4565b610bde81613b79565b6003600093015b818410610bf6575050505001610adf565b90919297610c2f869189610c20610c0e8d888a613541565b35610c1a875482613bf4565b86613551565b50610c2a81613c0a565b613c3a565b9801929190610be5565b60046040517f1bbee726000000000000000000000000000000000000000000000000000000008152fd5b346103365760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657600435602435610ca18161044b565b60009180835282602052610cbb600160408520015461406c565b8083528260205260ff610cf183604086209073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b541615610cfc578280f35b80835282602052610d3082604085209073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b60017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082541617905573ffffffffffffffffffffffffffffffffffffffff339216907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d8480a438808280f35b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60209101126103365760043561ffff811681036103365790565b3461033657610de536610d9c565b610ded613b17565b61ffff8116906109c4821161051f577fede4aee4284b8033b84c1aadcc51b229a4e46e6b42ab40092e237f07508b4626916020917fffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffff72ffff00000000000000000000000000000000006003549260881b16911617600355604051908152a1005b346103365760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657610ea4613b17565b60025460ff811615610f3e575060025460ff811615610f14577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166002557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6020604051338152a16107626141ea565b60046040517f6cd60201000000000000000000000000000000000000000000000000000000008152fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00600191610f6a6143ee565b16176002557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a1005b346103365760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657602435610fd68161044b565b3373ffffffffffffffffffffffffffffffffffffffff821603610fff5761076290600435614286565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c6600000000000000000000000000000000006064820152fd5b34610336576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657600435906110bf613b17565b81156111905764ffffffffff60035460a81c169060005b83811061114a576107627fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85857f0c4874e1a947afdb9c813baf258eec6a442b25531183f82046efc9760f6407736040518061114085858360209093929193604081019481520152565b0390a10101614a7f565b8060019184016000526008835261118a604060002060047fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b016110d6565b63cbc4e0606000526004601cfd5b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60209101126103365760043564ffffffffff811681036103365790565b34610336576111ea3661119e565b6111f2613b17565b64ffffffffff811690610e10821161051f577fbdeccc4cf4c928bfff2005eee2fd4b91bb3d22035af62a93e35b1eedf853e3a3916020917fffffffffffffffffffffffffffffff0000000000ffffffffffffffffffffffff70ffffffffff0000000000000000000000006003549260601b16911617600355604051908152a1005b346103365760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610336576004356bffffffffffffffffffffffff8116809103610336576112c3613b17565b801561051f576020817f988fd919afedb9b211cf201222b0091d485871857d14d2a87946e1ee390a17f4927fffffffffffffffffffffffffffffffffffffffff0000000000000000000000006003541617600355604051908152a1005b346103365760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657602073ffffffffffffffffffffffffffffffffffffffff60065416604051908152f35b346103365760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610336576004356113ad8161044b565b6113b5613b17565b6002549073ffffffffffffffffffffffffffffffffffffffff8260081c1661141e5774ffffffffffffffffffffffffffffffffffffffff007fffffffffffffffffffffff0000000000000000000000000000000000000000ff9160081b16911617600255600080f35b63d6336f0d6000526004601cfd5b9060407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc83011261033657600435916024359067ffffffffffffffff82116103365761147a91600401610a2c565b9091565b6114873661142c565b600192919290600260015414610c395760026001556114a46143ee565b80156115f9576114be836000526008602052604060002090565b936114c885614424565b6114d18561446c565b60006114dc836136e7565b9360005b84811061156a5750503403611565576115227fa315167fc4200676e8597c5df065fafa8cecfeac15a8e2aded299a649e4a5175936040519384938733866137e4565b0390a1611547825464ffffffffff90600385015491808260081c169160901c1661472d565b611555575b61076260018055565b61155e91614764565b388061154c565b61051f565b80870190611582826000526008602052604060002090565b916115936108878585015460a01c90565b9081156115e8575b6115a584826145b3565b6115b0838989613541565b35906115bc8383613765565b61156557816115d6936115d09288976146a5565b956137b6565b936115e182896137d0565b52016114e0565b90506115f3816144cf565b9061159b565b614362565b346103365760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657602061ffff60035460981c16604051908152f35b346103365760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657602060ff600254166040519015158152f35b346103365760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657600435600052600a602052606060406000206001815491015464ffffffffff6040519260ff81161515845260081c1660208301526040820152f35b346103365760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657602073ffffffffffffffffffffffffffffffffffffffff60055416604051908152f35b34610336576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126117ed57600260015414610c39576002600155611785613b5e565b64ffffffffff8060035460a81c1690818352600860205260408320906117aa82613bb2565b6117b981835460681c16613858565b1642106117e057906117ce816117d3936149c0565b614a7f565b506117dd60018055565b80f35b63f4c0ca6e83526004601cfd5b80fd5b346103365760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103365773ffffffffffffffffffffffffffffffffffffffff6004356118408161044b565b611848613b17565b16801561051f576020817f2d5eba1cf3f9252b2aa813087328fc416c6c2ad0fb1417f9f5f78f08cb24cfdb927fffffffffffffffffffffffff00000000000000000000000000000000000000006005541617600555604051908152a1005b346103365760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103365773ffffffffffffffffffffffffffffffffffffffff6004356118f68161044b565b6118fe613b17565b16801561051f576020817fa75f06c1fcb711f11e4fe2a1e8b84e798cce8ea1c6d6db252abe31ebd836e21f927fffffffffffffffffffffffff00000000000000000000000000000000000000006006541617600655604051908152a1005b346103365760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657602064ffffffffff60065460a01c16604051908152f35b8015150361033657565b60407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc820112610336576004359067ffffffffffffffff8211610336576119f591600401610a2c565b9091602435611a03816119a2565b90565b3461033657611a14366119ac565b60009291839284915b808310611a6d57505050600014611a4f5750611a3b611a4b91614ba6565b6040519081529081906020820190565b0390f35b80821015611a63575050611a4b6000611a3b565b611a4b9103611a3b565b909194611a7b86838561349f565b611aa7611a9382356000526008602052604060002090565b91611a9d83613bc8565b60208101906134e4565b600383019081549160005b828110611ad85750505050506001916002611acf920154906137b6565b95019190611a1d565b611ae3818487613541565b3584811015611b2d57611af69083613551565b50805460ff16611b058161209a565b15611b14575b50600101611ab2565b6001919b6002611b26920154906137b6565b9a90611b0b565b613bfc565b611b3b366119ac565b91600292600193600260015414610c39576002600155611b59613b5e565b611b61613446565b91600095869282611b7188613b79565b611ce8575b875b878110611c515750505081611bcf575b5050928360207ffbb3d671e318a7ebc6333ba95648c22dc746b01f141b5e81939d55d4664be29595015180610b6e57505080610b3b5750610b2f60405192839233846136ba565b15611c085790611c007ffbb3d671e318a7ebc6333ba95648c22dc746b01f141b5e81939d55d4664be2959592614caa565b909338611b88565b80611c15611c1c92614c32565b349061389d565b848111611c4c577ffbb3d671e318a7ebc6333ba95648c22dc746b01f141b5e81939d55d4664be295940390611c00565b614370565b611c5c81898961349f565b611c87611c7482356000526008602052604060002090565b91611c7e83613bc8565b611a9d83614c02565b90611c9182613b79565b600091600384015b818410611cbf5750505050906000611cb784869401978854906137b6565b965501611b78565b9091929c611cde88918f611cd8610c0e8f92888a613541565b50613c3a565b9d01929190611c99565b3415611b765761051f565b346103365760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657600480359060243567ffffffffffffffff811161033657611d47903690600401610a2c565b9160443590611d55826119a2565b6002916001600260015414610c39576002600155611d716143ee565b6000938493611d7f88613b79565b855b888110611ed6575050505081611ea5575b5050611da8846000526008602052604060002090565b611db181614424565b611dbb81866145b3565b611dc48161446c565b611dd5610887600183015460a01c90565b94611de08684613765565b80611e66575b5085831061156557611e1e610b2f937fecd5c5544dcd4a5344389c360ff979c215f25290177e786ca2c407e58a95b88a9783856146a5565b9181611e42825464ffffffffff90600385015491808260081c169160901c1661472d565b611e56575b505060405194859433866138aa565b611e5f91614764565b3881611e47565b9283611e9f91611e74613b5e565b03935a90337f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2613f36565b38611de6565b15611eba57611eb390614caa565b3880611d92565b908181106000036143705781611ed1910391614c32565b611eb3565b611ee1818a8a61349f565b611ef681356000526008602052604060002090565b90611f02825460ff1690565b91611f0c8361207e565b60039182841061204a57611f3890611f238561207e565b838514612029575b60208195939501906134e4565b9092611f4382613b79565b806000950192878114935b838710611f6357505050505050508301611d81565b9091929394959c611f8a611f788f878a613541565b35611f84845482613bf4565b83613551565b50611f9481614dd5565b805460ff16611fa28161209a565b612024578b918b6120099289611fb78861207e565b612016575b612001888201740100000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff825416179055565b0154906137b6565b9d01959493929190611f4e565b61201f81613c0a565b611fbc565b61437e565b61203283614c02565b60006120438985019c8d54906137b6565b9b55611f2b565b613ba4565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6005111561208857565b61204f565b9060058210156120885752565b6003111561208857565b969893959097949291926020610160610140996120c4818c81019d61208d565b829a64ffffffffff8098168483015261ffff6040971660408301528760609b166060830152876080951660808301528760a0961660a083015260c09873ffffffffffffffffffffffffffffffffffffffff9e8f1660c08401526bffffffffffffffffffffffff60e09b1660e08401526101008301526101208201528d51809c52019b01996000975b8a89106121625750505050505050505050505090565b909192939495969798999a9b8a896001928f8b8b915180516121838161209a565b8452808601518916868501528b8101518c85015287810151888501528981015189168a8501528a81015115158b8501520151168b820152019d019b9a9901979695949392919061214c565b346103365760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103365760043560008181526008602052604090208054603081901c61ffff16929091611a4b9190612233905460401c64ffffffffff1690565b9061225961224b826000526008602052604060002090565b5460681c64ffffffffff1690565b61227e612270836000526008602052604060002090565b5460901c64ffffffffff1690565b6122b26001612297856000526008602052604060002090565b015473ffffffffffffffffffffffffffffffffffffffff1690565b906122d460016122cc866000526008602052604060002090565b015460a01c90565b9261230c600361230660026122f3896000526008602052604060002090565b0154976000526008602052604060002090565b016138e9565b95604051998960ff64ffffffffff8d9c60081c1691168b6120a4565b34610336576123363661119e565b61233e613b17565b64ffffffffff8116906002821061051f577f32e1033127c5a25fa4a87832fb767338db2bca3d4eba8f34be6d5a8f71e92275916020917fff0000000000ffffffffffffffffffffffffffffffffffffffffffffffffffff7effffffffff00000000000000000000000000000000000000000000000000006003549260d01b16911617600355604051908152a1005b346103365760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657602060ff61244260243561240e8161044b565b6004356000526000845260406000209073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b54166040519015158152f35b346103365760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657602061ffff60035460881c16604051908152f35b346103365760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657602064ffffffffff60035460a81c16604051908152f35b346103365760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657602060405160008152f35b346103365760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103365760206bffffffffffffffffffffffff60035416604051908152f35b346103365760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103365760206125cf60243561259b8161044b565b6004356000526009835260406000209073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b54604051908152f35b34610336576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126117ed57600260015414610c3957600260015561261f6143ee565b64ffffffffff8060035460a81c168083526008602052604083209161264383613bde565b825490808260901c16916126686126646003870154848460081c168661472d565b1590565b612682575b50505061267991614764565b6117dd60018055565b60401c1642106126a05760021161269b5738808061266d565b61439a565b61438c565b346103365760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103365773ffffffffffffffffffffffffffffffffffffffff6004356126f58161044b565b16600052600b60205260406000206024356000526020526020604060002054604051908152f35b34610336577ff020ff23e722cd62b0e67a05c051cc3dc4b4d0c48e01de57a0571ad6a180c35d602061274d3661119e565b612755613b17565b6006547fffffffffffffff0000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000008360a01b1691161760065564ffffffffff60405191168152a1005b34610336576127bc36610d9c565b6127c4613b17565b61ffff811690612710821161051f577f2e38c85b973ddf3d7c0cbd813bddb9b63db96d86ff7b6ccce361777d674d813c916020917fffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffff74ffff000000000000000000000000000000000000006003549260981b16911617600355604051908152a1005b61284f3661142c565b91600260015414610c395760026001556128676143ee565b61287b816000526008602052604060002090565b61288481614424565b61288e81836145b3565b6128978161446c565b60038101549360009081946128be6128b9866000526008602052604060002090565b6137a3565b9234612f6b5782156115f9575b82612956575b505050612920857f73a19dd210f1a7f902193214c0ee91dd35ee5b4d920cba8d519eca65a7b488ca96859355835464ffffffffff808260901c169161291683856152f6565b60081c169061472d565b612946575b50506040805133815260208101929092528101919091528060608101610b2f565b61294f91614764565b3881612925565b919061296182614df3565b926000905b838210612a51575050505073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000ea4af05656c17b90f4d64add29e1d16803b15610336576129f16000929183926040519485809481937f0ca8e8a80000000000000000000000000000000000000000000000000000000083523090339060048501614f0c565b03925af1958615612a4c57808593612920937f73a19dd210f1a7f902193214c0ee91dd35ee5b4d920cba8d519eca65a7b488ca99612a33575b509350966128d1565b80612a40612a469261055c565b806103fa565b38612a2a565b613af0565b93979298612a64828b859a949995614e8e565b94612a7160208701613a06565b946001612ad5612a8089614ece565b604051612ac281612a9660208201948d86613a10565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282610591565b5190206000526007602052604060002090565b5403612f6657612b1884612b098873ffffffffffffffffffffffffffffffffffffffff16600052600b602052604060002090565b90600052602052604060002090565b546002612b2489614ece565b612b2d8161209a565b03612d11578015612ccd575b612b5a90612b546108876001899e959798969e015460a01c90565b90613b0d565b93612b6485615399565b612b7b612b7460408a018a6134e4565b90506136e7565b9a6000945b612b8d60408b018b6134e4565b9050861015612c39578c83808d898b98968f9a988e612bad8c859a6137b6565b9b612bb7936153ae565b9960408101612bc5916134e4565b612bcf9291613541565b3591612be59160005260206000209060021b0190565b3379ffffffffff00000000000000000000000000000000000000000060a88b901b16176003820155600260088e901b1781556001015560010196612c28916137d0565b600190526001019491939092612b80565b9c98612cb2929e965060019550612c79612c9a92989c959d9499612c5d878d6137d0565b519073ffffffffffffffffffffffffffffffffffffffff169052565b612c906020612c88878d6137d0565b510160019052565b60408101906134e4565b91906040612ca8868c6137d0565b51019236916105ea565b90526060612cc083896137d0565b5101525b01909291612966565b50612b5a612cda8861544c565b80612d0987612b098b73ffffffffffffffffffffffffffffffffffffffff16600052600b602052604060002090565b559050612b39565b6001612d278994979b959e969c98939d99614ece565b612d308161209a565b14612d41575b505050600190612cc4565b919a829c939c95919515612f25575b612d67612d6060408e018e6134e4565b36916105ea565b6001815103612f2057612d7c612d84916137c3565b518094613ac4565b6040517f313ce56700000000000000000000000000000000000000000000000000000000815260208160048173ffffffffffffffffffffffffffffffffffffffff8c165afa8015612a4c576108876001612df38f9495612b54612b5495612dfc98600091612ef1575b50613afc565b93015460a01c90565b9b612e068d615399565b60608101358d10612eec5784918d8f8b8e948b612e2384846137d0565b5173ffffffffffffffffffffffffffffffffffffffff9091169052612e4883836137d0565b516020016000905260408101612e5d916134e4565b92612e6891926137d0565b51606001913690612e78926105ea565b9052612e83916137b6565b9c612e8d936153ae565b93612ea3838960005260206000209060021b0190565b3379ffffffffff00000000000000000000000000000000000000000060a888901b16176003820155916002830155612ee0919060081b6001179055565b60010198388080612d36565b6143a8565b612f13915060203d602011612f19575b612f0b8183610591565b810190613ad7565b38612ded565b503d612f01565b613b80565b9150612f3085615082565b9182612f608c612b098973ffffffffffffffffffffffffffffffffffffffff16600052600b602052604060002090565b55612d50565b615074565b509450612f7f610887600185015460a01c90565b612f898134613765565b61156557612f979034613b0d565b946001612fa587898761532d565b97612fee612fbe828760005260206000209060021b0190565b3379ffffffffff00000000000000000000000000000000000000000060a88d901b16176003820155349060020155565b01966128cb565b6003111561033657565b346103365760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103365760043567ffffffffffffffff81116103365761304e903690600401610a2c565b6024359161305b83612ff5565b60443592613068846119a2565b61307061502d565b6130798161209a565b8015612f665760005b8381106130c157507f14f4f9b9a2d50cb168899c4825e24b7ffdc472b1dca88ddad74a834f7b62470b936130bc9160405194859485613a51565b0390a1005b600190600086156131465750815b61313f6130e56130e0848989613541565b613a06565b60ff6040519361312a856130fe8a602083019687613a10565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101875286610591565b16925190206000526007602052604060002090565b5501613082565b6130cf565b34610336577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60408136011261033657600435906024359067ffffffffffffffff82116103365760a09082360301126103365773ffffffffffffffffffffffffffffffffffffffff91602061321e6131c560248501613a06565b936131f484612b098773ffffffffffffffffffffffffffffffffffffffff16600052600b602052604060002090565b5490811561328d575b6132118160446132179301906004016134e4565b90613538565b3590613ac4565b926004604051809681937f313ce567000000000000000000000000000000000000000000000000000000008352165afa928315612a4c5761088760016122cc61327c611a3b96612b54611a4b99612b5497600091612ef15750613afc565b946000526008602052604060002090565b905061321761321161329e87615082565b929150506131fd565b346103365760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610336576107626024356004356132e88261044b565b80600052600060205261330260016040600020015461406c565b614286565b34610336576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126117ed57600260015414610c3957600260015561334e613b5e565b64ffffffffff8060035460a81c168083526008602052604083209161337283613bde565b8254818160401c1680159081156133b5575b506133a8579060019160901c16116133a3576117ce816117d3936149c0565b6143b6565b63f9ad93f585526004601cfd5b9050421038613384565b346103365760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657602064ffffffffff60035460601c16604051908152f35b346103365760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657602060035460f81c6040519015158152f35b604051906040820182811067ffffffffffffffff8211176105705760405260006020838281520152565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b91908110156134df5760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc181360301821215610336570190565b613470565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610336570180359067ffffffffffffffff821161033657602001918160051b3603831361033657565b90156134df5790565b91908110156134df5760051b0190565b80548210156134df5760005260206000209060021b0190600090565b90918281527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83116103365760209260051b809284830137010190565b908290808452602080940193600592818360051b82010195856000925b8584106135d957505050505050505090565b90919293949596977fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082820301845288357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc18436030181121561033657830160409080358352878101357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18236030181121561033657019087823592019267ffffffffffffffff831161033657828b1b3603841361033657600193899383838695866136a8960152019161356d565b9a0194019401929695949391906135c7565b60409073ffffffffffffffffffffffffffffffffffffffff611a03959316815281602082015201916135aa565b906136f1826105d2565b6136fe6040519182610591565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061372c82946105d2565b0190602036910137565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b811561376f570690565b613736565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b90600382018092116137b157565b613774565b919082018092116137b157565b8051156134df5760200190565b80518210156134df5760209160051b010190565b92909373ffffffffffffffffffffffffffffffffffffffff61381d9395168452602094602085015260806040850152608084019161356d565b9060608183039101526020808451928381520193019160005b828110613844575050505090565b835185529381019392810192600101613836565b9062015f9064ffffffffff809316019182116137b157565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82019182116137b157565b919082039182116137b157565b9160609373ffffffffffffffffffffffffffffffffffffffff6138df93989796981684526080602085015260808401916135aa565b9460408201520152565b9081546138f5816105d2565b926040936139066040519182610591565b82815280946020809201926000526020600020906000935b85851061392d57505050505050565b600484600192845161393e81610575565b6139f864ffffffffff88546139e460ff80831661395a8161209a565b865261399873ffffffffffffffffffffffffffffffffffffffff809460081c168988019073ffffffffffffffffffffffffffffffffffffffff169052565b898c01548b87015260028c015460608701526139d460038d0154938416608088019073ffffffffffffffffffffffffffffffffffffffff169052565b60a083811c909116151590860152565b60a81c1660c083019064ffffffffff169052565b81520193019401939161391e565b35611a038161044b565b90917fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060159360601b168252613a458161209a565b60f81b60148201520190565b929493918060608501606086525260808401919060005b818110613a8c575050509060409194613a808161209a565b60208401521515910152565b90919260019073ffffffffffffffffffffffffffffffffffffffff8535613ab28161044b565b16815260209081019401929101613a68565b818102929181159184041417156137b157565b90816020910312610336575160ff811681036103365790565b6040513d6000823e3d90fd5b60ff16604d81116137b157600a0a90565b811561376f570490565b3360009081527fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5602052604090205460ff1615613b5057565b6330cd74716000526004601cfd5b60035460f81c15613b6b57565b63010a265a6000526004601cfd5b15613b8057565b63947d5a846000526004601cfd5b5460ff16600581101561208857600403613ba457565b63f525e3206000526004601cfd5b5460ff16600581101561208857600203613ba457565b5460ff16600581101561208857600303613ba457565b5460ff16600581101561208857600103613ba457565b1015613bfc57565b6363df81716000526004601cfd5b6003015473ffffffffffffffffffffffffffffffffffffffff163303613c2c57565b633cc50b456000526004601cfd5b90613c4482614dd5565b613c8a60038301740100000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff825416179055565b815460ff8116613c998161209a565b80613cae5750505060020154611a03916137b6565b613cba8194939461209a565b60028103613cf45750508054611a03925060019060081c73ffffffffffffffffffffffffffffffffffffffff1691015490339030906151a6565b80613d0060019261209a565b14613d0c575b50505090565b73ffffffffffffffffffffffffffffffffffffffff809160081c16613d45845173ffffffffffffffffffffffffffffffffffffffff1690565b9182168103613d6f57505060206002613d6492015492019182516137b6565b90525b388080613d06565b613da29084602060029594960195865180613dab575b50509073ffffffffffffffffffffffffffffffffffffffff169052565b01549052613d67565b613db6913390613e3c565b3880613d85565b67ffffffffffffffff811161057057601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b3d15613e22573d90613e0882613dbd565b91613e166040519384610591565b82523d6000602084013e565b606090565b908160209103126103365751611a03816119a2565b919091803b15613f0c576040517fa9059cbb000000000000000000000000000000000000000000000000000000006020820190815273ffffffffffffffffffffffffffffffffffffffff9094166024820152604481019290925260009283928390613eaa8160648101612a96565b51925af1613eb6613df7565b9015613ee257805180613ec7575050565b8160208061266493613edc9501019101613e27565b613ee257565b60046040517ff1568f95000000000000000000000000000000000000000000000000000000008152fd5b60046040517f09ee12d5000000000000000000000000000000000000000000000000000000008152fd5b613f4b82849395600080809781948294f11590565b613f56575b50505050565b73ffffffffffffffffffffffffffffffffffffffff16803b1561406857604051937fd0e30db0000000000000000000000000000000000000000000000000000000008552838560048186865af1938415612a4c5761400f95602095614055575b506040518096819582947fa9059cbb000000000000000000000000000000000000000000000000000000008452600484016020909392919373ffffffffffffffffffffffffffffffffffffffff60408201951681520152565b03925af18015612a4c57614026575b808080613f50565b6140479060203d60201161404e575b61403f8183610591565b810190613e27565b503861401e565b503d614035565b80612a406140629261055c565b38613fb6565b8280fd5b80600052600060205260ff6140a53360406000209073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b5416156140af5750565b33906140b96156cb565b9160306140c5846137c3565b5360786140d1846156f8565b5360295b6001811161419c5761419861413d61416686612a966140fd886140f88915615744565b6157a9565b614137604051958694614137602087016017907f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081520190565b9061528b565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000815260110190565b6040519182917f08c379a0000000000000000000000000000000000000000000000000000000008352600483016152e5565b0390fd5b90600f81169060108210156134df577f30313233343536373839616263646566000000000000000000000000000000006141e5921a6141db8487615708565b5360041c91615719565b6140d5565b64ffffffffff60035460a81c166000805b6001811061424157505061423e907f0c4874e1a947afdb9c813baf258eec6a442b25531183f82046efc9760f6407736040805183815260016020820152a1614a7f565b50565b806001918401835260086020526142806040842060047fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b016141fb565b6000908082528160205260ff6142bf84604085209073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b54166142ca57505050565b808252816020526142fe83604084209073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0081541690557ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b73ffffffffffffffffffffffffffffffffffffffff3394169280a4565b63a95231d56000526004601cfd5b630134f2786000526004601cfd5b63a1e9dd9d6000526004601cfd5b63f9ad93f56000526004601cfd5b637e439aed6000526004601cfd5b63f48cb8a06000526004601cfd5b637cd9dd6a6000526004601cfd5b63f90121326000526004601cfd5b63c11f59766000526004601cfd5b630da5618b6000526004601cfd5b60ff600254166143fa57565b60046040517f1309a563000000000000000000000000000000000000000000000000000000008152fd5b5460ff811660058110156120885760011490811591614445575b50613ba457565b60401c64ffffffffff16801515915081614461575b503861443e565b90504210153861445a565b805464ffffffffff808260401c161561448457505050565b60035460601c1642018042116137b1576cffffffffff00000000000000007fffffffffffffffffffffffffffffffffffffff0000000000ffffffffffffffff9160401b169116179055565b9060035460017fffffffffffffffffffffffff00000000000000000000000000000000000000006145196bffffffffffffffffffffffff8416956000526008602052604060002090565b9267ffff0000000000008160581c1665ffffffffff008260c81c1617845560a01b16910155565b9060035460017fffffffffffffffffffffffff000000000000000000000000000000000000000061458a6bffffffffffffffffffffffff8416956000526008602052604060002090565b928267ffff0000000000008260581c1665ffffffffff008360c81c161717845560a01b16910155565b8060005260096020526145e960406000203373ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b54908115614630575b6001925060005260096020520161462d3360406000209073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b55565b82549264ffffffffff93848160901c16948160081c168514614697577fffffffffffffffffff0000000000ffffffffffffffffffffffffffffffffffff16600194850160901b76ffffffffff000000000000000000000000000000000000161790556145f2565b63b53a57db6000526004601cfd5b9091939293801561376f5784049360038201549160018301936146f36146e2888664ffffffffff956146dd87825460901c168b6152f6565b61532d565b916000526008602052604060002090565b93600385018095116137b15760029261471a614728928760005260206000209060021b0190565b921660a81b33176003830155565b015555565b919082109182159261473e57505090565b60011091508161474c575090565b60649150101590565b90816020910312610336575190565b6147b3906147728382614a22565b80547fffffffffffffffffffffffffffff0000000000ffffffffffffffffffffffffff164260681b71ffffffffff0000000000000000000000000016179055565b6040517f5d3b1d300000000000000000000000000000000000000000000000000000000081527f8af398995b04c28e9951adb9721ef74c74f93e6a478f39e7e0777be13527e7ef60048201527f00000000000000000000000000000000000000000000000000000000000002de67ffffffffffffffff1660248201527f000000000000000000000000000000000000000000000000000000000000000361ffff1660448201526207a12060648201526001608482015260208160a48160007f000000000000000000000000271682deb8c4e0901d1a1550ad2e64d568e6990973ffffffffffffffffffffffffffffffffffffffff165af1908115612a4c57600091614934575b506148d16106f182600052600a602052604060002090565b61492f577f3d94fecedaa4f90b8bd459797adb95f5bb11426025c5541390d9ccc1ad1b60a19181600052600a60205260406000208160081b600117905561492a6040519283928360209093929193604081019481520152565b0390a1565b6143c4565b614956915060203d60201161495c575b61494e8183610591565b810190614755565b386148b9565b503d614944565b7ffbe046f0ca401af45e57af7a8efd3840294bfc077bf062f4b9919e2c028e161c9160409160037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055815190815260036020820152a1565b7ffbe046f0ca401af45e57af7a8efd3840294bfc077bf062f4b9919e2c028e161c91614a1360409260047fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b815190815260046020820152a1565b7ffbe046f0ca401af45e57af7a8efd3840294bfc077bf062f4b9919e2c028e161c9160409160027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055815190815260026020820152a1565b600101906003547fffffffffffff0000000000ffffffffffffffffffffffffffffffffffffffffff79ffffffffff0000000000000000000000000000000000000000008460a81b1691161780600355614ae2836000526008602052604060002090565b6bffffffffffffffffffffffff614afd600183015460a01c90565b16614b48575050614b0d82614540565b505b60408051838152600160208201527ffbe046f0ca401af45e57af7a8efd3840294bfc077bf062f4b9919e2c028e161c918190810161492a565b54614b5c9060901c64ffffffffff16610726565b90614b71846000526008602052604060002090565b908154906001821793614b87575b505055614b0f565b600192935064ffffffffff9060601c16420160401b1717903880614b7f565b670de0b6b3a764000090808202918204036137b157614bcf9061ffff60035460981c1690613ac4565b614bf373ffffffffffffffffffffffffffffffffffffffff60025460081c16615082565b801561376f5761271091040490565b6001015473ffffffffffffffffffffffffffffffffffffffff163303614c2457565b63618c72426000526004601cfd5b60407fa0c67dacab0c86ad0a872c2ed3fa9deb08f80f4f0543d481f2fac9ee41d0269191614c9b73ffffffffffffffffffffffffffffffffffffffff60045416825a917f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2613f36565b815190815260006020820152a1565b614cb390614ba6565b73ffffffffffffffffffffffffffffffffffffffff90817f00000000000000000000000000000000000ea4af05656c17b90f4d64add29e1d16918060025460081c169060045416833b156103365760846000928360405196879485937fda3e8ce4000000000000000000000000000000000000000000000000000000008552600485015233602485015260448401528660648401525af1918215612a4c577fa0c67dacab0c86ad0a872c2ed3fa9deb08f80f4f0543d481f2fac9ee41d0269192614dc2575b5060025460081c73ffffffffffffffffffffffffffffffffffffffff166040805192835273ffffffffffffffffffffffffffffffffffffffff90911660208301528190810161492a565b80612a40614dcf9261055c565b38614d78565b6003015460a01c60ff16614de557565b636507689f6000526004601cfd5b90614dfd826105d2565b604090614e0d6040519182610591565b8381527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0614e3b82956105d2565b01906000805b838110614e4f575050505050565b845190608082019180831067ffffffffffffffff8411176105705760209287528381528284818301526060808984015280830152828601015201614e41565b91908110156134df5760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6181360301821215610336570190565b35611a0381612ff5565b90815180825260208080930193019160005b828110614ef8575050505090565b835185529381019392810192600101614eea565b93919392909260609460608201606083528551809152608090608084019760808260051b860101986020809901936000925b848410614f925750505050505090614f74604092614f90959683019073ffffffffffffffffffffffffffffffffffffffff169052565b019073ffffffffffffffffffffffffffffffffffffffff169052565b565b90919293949a8a8061501d838f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff808d60019703018952519073ffffffffffffffffffffffffffffffffffffffff825116815283820151614ff18161209a565b848201528661500d60408a81860151918501528a840190614ed8565b9201519087818403910152614ed8565b9d01940194019294939190614f3e565b3360009081527fee57cd81e84075558e8fcc182a1f4393f91fc97f963a136e66b7f949a62f319f602052604090205460ff161561506657565b637c214f046000526004601cfd5b63c1ab6dc16000526004601cfd5b602073ffffffffffffffffffffffffffffffffffffffff604481600554169360405194859384927fe3cae776000000000000000000000000000000000000000000000000000000008452166004830152610e1060248301525afa908115612a4c576000916150ee575090565b611a03915060203d60201161495c5761494e8183610591565b805191821561519e576000925b80841061517057508215159182615152575b505015611a03577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b61516791925061516184613870565b906137d0565b51143880615126565b61517a81856156b6565b908261518683866137d0565b5111156151935750615114565b935060010192615114565b505050600090565b909192813b15613f0c576040519260208401947f23b872dd00000000000000000000000000000000000000000000000000000000865273ffffffffffffffffffffffffffffffffffffffff809216602486015216604484015260648301526064825260a082019282841067ffffffffffffffff851117610570576000809493819460405251925af1615236613df7565b501561523e57565b60046040517fe0f5c508000000000000000000000000000000000000000000000000000000008152fd5b60005b83811061527b5750506000910152565b818101518382015260200161526b565b9061529e60209282815194859201615268565b0190565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6020936152de81518092818752878088019101615268565b0116010190565b906020611a039281815201906152a2565b6064811161531f576064146153085750565b60011461531157565b63ae24220e6000526004601cfd5b6327e6fcc76000526004601cfd5b919061533882615399565b8061534a575064ffffffffff91501690565b600392837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61537b93019101613551565b5064ffffffffff928391015460a81c169081018091116137b1571690565b156153a057565b63f91214386000526004601cfd5b64ffffffffff939084169283156153ce5750508216019081116137b15790565b90919250611a03935061532d565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610336570180359067ffffffffffffffff82116103365760200191813603831361033657565b919082604091031261033657602082356154468161044b565b92013590565b9060808201357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8183360301811215610336578201916020809101356154908161044b565b604084013593428511801561568e575b61568957604051918261550f8582019283608060009193929373ffffffffffffffffffffffffffffffffffffffff60a08201957f60d14eec5d309c7bcbba8f8779f8070820b882731ce8afd4d9282a327dfe6ede835260016020840152610e1060408401521660608201520152565b03926155417fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe094858101835282610591565b51902090803582036156845761566f8461563161563d6156749673ffffffffffffffffffffffffffffffffffffffff9a61567c998701976155f461558f6155888b8b6153dc565b3691615846565b878151910120926155e86040519384928a8401964692889094939260809260a08301967f8c01f2233cc36f533c3fbfd8037c653a0326c46e0dc25bff9aea020c1a72a05484526020840152604083015260608201520152565b03848101835282610591565b5190209360405193849182019586603c917f19457468657265756d205369676e6564204d6573736167653a0a3332000000008252601c8201520190565b03908101835282610591565b51902060065473ffffffffffffffffffffffffffffffffffffffff1661566961558860608601866153dc565b916158a9565b6153dc565b81019061542d565b9216612f6657565b6143e0565b6143d2565b506156af6156a961072660065464ffffffffff9060a01c1690565b866137b6565b42116154a0565b90808216911860011c81018091116137b15790565b604051906060820182811067ffffffffffffffff82111761057057604052602a8252604082602036910137565b8051600110156134df5760210190565b9081518110156134df570160200190565b80156137b1577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b1561574b57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602060248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152fd5b604051906080820182811067ffffffffffffffff8211176105705760405260428252606036602084013760306157de836137c3565b5360786157ea836156f8565b536041905b6001821161580257611a03915015615744565b600f81169060108210156134df577f3031323334353637383961626364656600000000000000000000000000000000615840921a6141db8486615708565b906157ef565b92919261585282613dbd565b916158606040519384610591565b829481845281830111610336578281602093846000960137010152565b908160209103126103365751611a038161030c565b604090611a039392815281602082015201906152a2565b91813b615903576158ba91926159eb565b73ffffffffffffffffffffffffffffffffffffffff908116911614614f905760046040517fd1085d1b000000000000000000000000000000000000000000000000000000008152fd5b61595673ffffffffffffffffffffffffffffffffffffffff926020926040519485809481937f1626ba7e00000000000000000000000000000000000000000000000000000000998a845260048401615892565b0392165afa8015612a4c577fffffffff00000000000000000000000000000000000000000000000000000000916000916159bc575b501614614f905760046040517ff6cd0e2f000000000000000000000000000000000000000000000000000000008152fd5b6159de915060203d6020116159e4575b6159d68183610591565b81019061587d565b3861598b565b503d6159cc565b815160418103615b2e57506020820151916060604082015191015160001a925b7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08211615b045760ff8416601b8114159081615af8575b50615ac4576040805193845260ff9490941660208085019190915293830152606082015260008080529060809060015afa15612a4c576000519073ffffffffffffffffffffffffffffffffffffffff821615615a9a57565b60046040517ff05a20c7000000000000000000000000000000000000000000000000000000008152fd5b6040517f417893a400000000000000000000000000000000000000000000000000000000815260ff85166004820152602490fd5b601c9150141538615a42565b60046040517fc1851252000000000000000000000000000000000000000000000000000000008152fd5b60408103615b71575060406020830151920151601b7f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82169160ff1c0192615a0b565b6040517fd42b4bbd0000000000000000000000000000000000000000000000000000000081526004810191909152602490fdfea2646970667358221220119e9e5a46e5948caac21a0c13109c32fcd0da478b9c78f517652568b63f899d64736f6c63430008170033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000003ab105f0e4a22ec4a96a9b0ca90c5c534d21f3a70000000000000000000000003ab105f0e4a22ec4a96a9b0ca90c5c534d21f3a700000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000e10000000000000000000000000000000000000000000000000002386f26fc10000000000000000000000000000b5a9e5a319c7fda551a30be592c77394bf935c6f00000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000013888af398995b04c28e9951adb9721ef74c74f93e6a478f39e7e0777be13527e7ef00000000000000000000000000000000000000000000000000000000000002de000000000000000000000000271682deb8c4e0901d1a1550ad2e64d568e69909000000000000000000000000aeb1d03929bf87f69888f381e73fbf75753d75af00000000000000000000000000000000000ea4af05656c17b90f4d64add29e1d00000000000000000000000000000000000a95dbfc66d37f3fc5e597c0b03daf000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000005a0000000000000000000000000000000000000000000000000000000000000003
-----Decoded View---------------
Arg [0] : params (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
-----Encoded View---------------
17 Constructor Arguments found :
Arg [0] : 0000000000000000000000003ab105f0e4a22ec4a96a9b0ca90c5c534d21f3a7
Arg [1] : 0000000000000000000000003ab105f0e4a22ec4a96a9b0ca90c5c534d21f3a7
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000032
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000e10
Arg [4] : 000000000000000000000000000000000000000000000000002386f26fc10000
Arg [5] : 000000000000000000000000b5a9e5a319c7fda551a30be592c77394bf935c6f
Arg [6] : 00000000000000000000000000000000000000000000000000000000000001f4
Arg [7] : 0000000000000000000000000000000000000000000000000000000000001388
Arg [8] : 8af398995b04c28e9951adb9721ef74c74f93e6a478f39e7e0777be13527e7ef
Arg [9] : 00000000000000000000000000000000000000000000000000000000000002de
Arg [10] : 000000000000000000000000271682deb8c4e0901d1a1550ad2e64d568e69909
Arg [11] : 000000000000000000000000aeb1d03929bf87f69888f381e73fbf75753d75af
Arg [12] : 00000000000000000000000000000000000ea4af05656c17b90f4d64add29e1d
Arg [13] : 00000000000000000000000000000000000a95dbfc66d37f3fc5e597c0b03daf
Arg [14] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [15] : 000000000000000000000000000000000000000000000000000000000000005a
Arg [16] : 0000000000000000000000000000000000000000000000000000000000000003
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.