More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 607,743 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Draw Winner | 12748729 | 51 secs ago | IN | 0 ETH | 0.00000051 | ||||
Draw Winner | 12748666 | 2 mins ago | IN | 0 ETH | 0.0000005 | ||||
Draw Winner | 12748603 | 5 mins ago | IN | 0 ETH | 0.0000005 | ||||
Draw Winner | 12748540 | 7 mins ago | IN | 0 ETH | 0.0000005 | ||||
Draw Winner | 12748475 | 9 mins ago | IN | 0 ETH | 0.00000051 | ||||
Deposit | 12748449 | 10 mins ago | IN | 0.007 ETH | 0.00000057 | ||||
Claim Prizes | 12748419 | 11 mins ago | IN | 0 ETH | 0.00000106 | ||||
Draw Winner | 12748411 | 11 mins ago | IN | 0 ETH | 0.00000049 | ||||
Draw Winner | 12748348 | 13 mins ago | IN | 0 ETH | 0.00000048 | ||||
Draw Winner | 12748284 | 15 mins ago | IN | 0 ETH | 0.00000041 | ||||
Deposit | 12748271 | 16 mins ago | IN | 0.002 ETH | 0.00000053 | ||||
Draw Winner | 12748220 | 17 mins ago | IN | 0 ETH | 0.00000048 | ||||
Deposit | 12748219 | 17 mins ago | IN | 0.01 ETH | 0.00000009 | ||||
Deposit | 12748188 | 18 mins ago | IN | 0.005 ETH | 0.00000053 | ||||
Draw Winner | 12748156 | 19 mins ago | IN | 0 ETH | 0.00000047 | ||||
Draw Winner | 12748092 | 22 mins ago | IN | 0 ETH | 0.0000004 | ||||
Draw Winner | 12748029 | 24 mins ago | IN | 0 ETH | 0.00000047 | ||||
Deposit ETH Into... | 12747988 | 25 mins ago | IN | 0.651 ETH | 0.00002796 | ||||
Draw Winner | 12747965 | 26 mins ago | IN | 0 ETH | 0.00000046 | ||||
Claim Prizes | 12747960 | 26 mins ago | IN | 0 ETH | 0.00000366 | ||||
Draw Winner | 12747901 | 28 mins ago | IN | 0 ETH | 0.00000045 | ||||
Claim Prizes | 12747870 | 29 mins ago | IN | 0 ETH | 0.00000529 | ||||
Claim Prizes | 12747846 | 30 mins ago | IN | 0 ETH | 0.00000195 | ||||
Draw Winner | 12747838 | 30 mins ago | IN | 0 ETH | 0.00000043 | ||||
Deposit | 12747807 | 31 mins ago | IN | 0.028 ETH | 0.00000033 |
Latest 25 internal transactions (View All)
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
12748419 | 11 mins ago | 0.18612 ETH | ||||
12748419 | 11 mins ago | 0.00188 ETH | ||||
12747960 | 26 mins ago | 0.53658 ETH | ||||
12747960 | 26 mins ago | 0.00542 ETH | ||||
12747870 | 29 mins ago | 0.65142 ETH | ||||
12747870 | 29 mins ago | 0.00658 ETH | ||||
12747846 | 30 mins ago | 0.0594 ETH | ||||
12747846 | 30 mins ago | 0.0006 ETH | ||||
12747794 | 32 mins ago | 0.16632 ETH | ||||
12747794 | 32 mins ago | 0.00168 ETH | ||||
12747599 | 38 mins ago | 0.15444 ETH | ||||
12747599 | 38 mins ago | 0.00156 ETH | ||||
12747150 | 53 mins ago | 0.09702 ETH | ||||
12747150 | 53 mins ago | 0.00098 ETH | ||||
12747132 | 54 mins ago | 0.10593 ETH | ||||
12747132 | 54 mins ago | 0.00107 ETH | ||||
12747067 | 56 mins ago | 0.07425 ETH | ||||
12747067 | 56 mins ago | 0.00075 ETH | ||||
12747043 | 57 mins ago | 0.24948 ETH | ||||
12747043 | 57 mins ago | 0.00252 ETH | ||||
12747015 | 57 mins ago | 0.44253 ETH | ||||
12747015 | 57 mins ago | 0.00447 ETH | ||||
12746979 | 1 hrs ago | 0.06534 ETH | ||||
12746979 | 1 hrs ago | 0.00066 ETH | ||||
12746955 | 1 hrs ago | 0.198 ETH |
Latest 2 Deposits
L2 Txn Hash | L1 Deposit Txn | Value | Token | |
---|---|---|---|---|
0x12e0fdb894a7373b6573c010c8089c8bc9f94303a4c313f46f7a16769bc3e13c | 101 days ago | 0.01 | Ether (ETH) | |
0x8056eda977ece199672cf4a7fa5d0e4b15ed7216bdbf14d01b7c67c89e32ab6c | 101 days ago | 0.01 | Ether (ETH) |
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
BlastYoloLimit
Compiler Version
v0.8.23+commit.f704f362
Optimization Enabled:
Yes with 888888 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; import {YoloLimit} from "./YoloLimit.sol"; import {IBlast, YieldMode as IBlast__YieldMode, GasMode as IBlast__GasMode} from "./interfaces/IBlast.sol"; import {IBlastPoints} from "./interfaces/IBlastPoints.sol"; import {IERC20Rebasing, YieldMode as IERC20Rebasing__YieldMode} from "./interfaces/IERC20Rebasing.sol"; // @@@@@@@@@@@@@ @@@@@@@@@@@@@ // @@@@@@@@@@@@@@@ @@@@@@@@@@@@@@ @@@@%*+++++++++*%@@@@ @@@@@@@@@@@@@@ @@@@%+-:::::::-+%@@@@ // @#:........=@@ @@*.........+@@@@*=================*@@@ @@=........=@@ @@@+.................+@@@ // @@=........:#@@ @@.........:@@%+=====================+%@@ @@=........=@@ @@%-.....................-#@@ // @@%:........=@@ @@=........:%@*=========================+%@@@=........=@@ @@%-.........................=@@@ // @@+........:#@ @@#........:%%============================+#@@=........=@@ @@#:...........................:#@@ // @@:........+@@ @@:.......:#%%@#*=======*%%@@@%%*==========+%@=........=@@ @#:.........:=*%%@%%#=..........:#@@ // @@#........:%@ @@+........+%+==+#@@*==#@@@@ @@@@#=========+@#........=@@ @%-........:*@@@@ @@@@+:........-%@ // @@=........=@@@#:.......-%*=======*@@@@ @@@=========*@:.......+@@ @@*.........@@@ @@%:........+@@ // @%:.......:%@@=........=@+========*@@ @%=========@+.......+@@ @@-........%@@ @@*........=%@ // @@+:.....:.-@#:.:......+@@@@@@@@@@@@ @@%%%%%%%%#@#::....:+@@ @@:.:.....:@@ @@::.:..:.-%@ // @%-::::::::*-:::::::::@@*+++++++*@@ @@+++++++++@*:::::::+@@ @@:::::::::%@ @@%::::::::-%@ // @@%********=:::::::::*@@*+*#%@@@##@@ @@*========+@=:::::::+@@ @@=::::::::=@@ @@=::::::::+@@ // @@@@@@@@@@:::::::::=@@@@@#*++++++*@@ @@@+=========%@::::::::+@@ @%:::::::::=@@@ @@@=:::::::::#@@ // @@=:::::::::%@ @@*++++++++++*@@@@@@@@@*+========+#@+::::::::+%@@@@@@@%+::::::::::+@@@@@@@@@+::::::::::+@@ // @@#:::::::::*@@ @@*+++++++++*@#++++++==========+*@@+::::::::::::::::::::::::::::::::-===-::::::::::::=@@ // @@-::::::::-%@ @@#++++++++%%+===============+#@@@+::::::::::::::::::::::::::::::::::::::::::::::::*@@ // @@+:::::::::*@@ @@@*+++++%%+===============*%@@@@+:::::::::::::::::::::*=:::::::::::::::::::::::=%@@ // @%-::::::::=@@ @@@#++#@*+============+*@@@ @@+:::::::::::::::::::::%@%+-::::::::::::::::::+%@@ // @@%*********%@@ @@@@@*+==========+#@@@@ @@#*********************%@@@@@*-:::::::::::-*@@@@ // @@@@@@@@@@@@@@ @@@@@@@%%%@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@%%%@@@@@@@ // @@@@ @@@@@ /** * @title BlastYoloLimit * @notice This contract permissionlessly hosts yolos on Blast on YOLO Games. * @author YOLO Games protocol team */ contract BlastYoloLimit is YoloLimit { IERC20Rebasing private immutable WETH_YIELD_CONFIGURATION; IERC20Rebasing private immutable USDB_YIELD_CONFIGURATION; /** * @param params The constructor params. * @param _ethYieldConfiguration The ETH yield configuration. * @param _usdbYieldConfiguration The USDB yield configuration. * @param _blastPoints The Blast points configuration. * @param _blastPointsOperator The Blast points operator. */ constructor( ConstructorCalldata memory params, address _ethYieldConfiguration, address _usdbYieldConfiguration, address _blastPoints, address _blastPointsOperator ) YoloLimit(params) { IBlast(_ethYieldConfiguration).configure(IBlast__YieldMode.CLAIMABLE, IBlast__GasMode.CLAIMABLE, params.owner); IERC20Rebasing(params.weth).configure(IERC20Rebasing__YieldMode.CLAIMABLE); IERC20Rebasing(_usdbYieldConfiguration).configure(IERC20Rebasing__YieldMode.CLAIMABLE); IBlastPoints(_blastPoints).configurePointsOperator(_blastPointsOperator); WETH_YIELD_CONFIGURATION = IERC20Rebasing(params.weth); USDB_YIELD_CONFIGURATION = IERC20Rebasing(_usdbYieldConfiguration); } /** * @param wethReceiver The receiver of WETH. * @param usdbReceiver The receiver of USDB. */ function claim(address wethReceiver, address usdbReceiver) external { _validateIsOwner(); uint256 claimableWETH = WETH_YIELD_CONFIGURATION.getClaimableAmount(address(this)); if (claimableWETH != 0) { WETH_YIELD_CONFIGURATION.claim(wethReceiver, claimableWETH); } uint256 claimableUSDB = USDB_YIELD_CONFIGURATION.getClaimableAmount(address(this)); if (claimableUSDB != 0) { USDB_YIELD_CONFIGURATION.claim(usdbReceiver, claimableUSDB); } } }
// 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.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 call recipient is not a contract. */ error NotAContract();
// 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 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; interface IERC1271 { function isValidSignature(bytes32 hash, bytes calldata signature) external view returns (bytes4 magicValue); }
// 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; interface IERC721 { event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); event ApprovalForAll(address indexed owner, address indexed operator, bool approved); function balanceOf(address owner) external view returns (uint256 balance); function ownerOf(uint256 tokenId) external view returns (address owner); function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; function safeTransferFrom(address from, address to, uint256 tokenId) external; function transferFrom(address from, address to, uint256 tokenId) external; function approve(address to, uint256 tokenId) external; function setApprovalForAll(address operator, bool _approved) external; function getApproved(uint256 tokenId) external view returns (address operator); function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity >=0.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; /** * @title IReentrancyGuard * @author LooksRare protocol team (👀,💎) */ interface IReentrancyGuard { /** * @notice This is returned when there is a reentrant call. */ error ReentrancyFail(); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; // Interfaces import {IERC20} from "../interfaces/generic/IERC20.sol"; // Errors import {ERC20TransferFail, ERC20TransferFromFail} from "../errors/LowLevelErrors.sol"; import {NotAContract} from "../errors/GenericErrors.sol"; /** * @title LowLevelERC20Transfer * @notice This contract contains low-level calls to transfer ERC20 tokens. * @author LooksRare protocol team (👀,💎) */ contract LowLevelERC20Transfer { /** * @notice Execute ERC20 transferFrom * @param currency Currency address * @param from Sender address * @param to Recipient address * @param amount Amount to transfer */ function _executeERC20TransferFrom(address currency, address from, address to, uint256 amount) internal { if (currency.code.length == 0) { revert NotAContract(); } (bool status, bytes memory data) = currency.call(abi.encodeCall(IERC20.transferFrom, (from, to, amount))); if (!status) { revert ERC20TransferFromFail(); } if (data.length > 0) { if (!abi.decode(data, (bool))) { revert ERC20TransferFromFail(); } } } /** * @notice Execute ERC20 (direct) transfer * @param currency Currency address * @param to Recipient address * @param amount Amount to transfer */ function _executeERC20DirectTransfer(address currency, address to, uint256 amount) internal { if (currency.code.length == 0) { revert NotAContract(); } (bool status, bytes memory data) = currency.call(abi.encodeCall(IERC20.transfer, (to, amount))); if (!status) { revert ERC20TransferFail(); } if (data.length > 0) { if (!abi.decode(data, (bool))) { revert ERC20TransferFail(); } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; // Interfaces import {IERC721} from "../interfaces/generic/IERC721.sol"; // Errors import {ERC721TransferFromFail} from "../errors/LowLevelErrors.sol"; import {NotAContract} from "../errors/GenericErrors.sol"; /** * @title LowLevelERC721Transfer * @notice This contract contains low-level calls to transfer ERC721 tokens. * @author LooksRare protocol team (👀,💎) */ contract LowLevelERC721Transfer { /** * @notice Execute ERC721 transferFrom * @param collection Address of the collection * @param from Address of the sender * @param to Address of the recipient * @param tokenId tokenId to transfer */ function _executeERC721TransferFrom(address collection, address from, address to, uint256 tokenId) internal { if (collection.code.length == 0) { revert NotAContract(); } (bool status, ) = collection.call(abi.encodeCall(IERC721.transferFrom, (from, to, tokenId))); if (!status) { revert ERC721TransferFromFail(); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; // Interfaces import {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; /** * @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 {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; // 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.20; enum TokenType { ERC20, ERC721, ERC1155 }
// 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 // 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 // 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 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 v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (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 (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 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.23; enum YieldMode { AUTOMATIC, VOID, CLAIMABLE } enum GasMode { VOID, CLAIMABLE } interface IBlast { // configure function configureContract(address contractAddress, YieldMode _yield, GasMode gasMode, address governor) external; function configure(YieldMode _yield, GasMode gasMode, address governor) external; // base configuration options function configureClaimableYield() external; function configureClaimableYieldOnBehalf(address contractAddress) external; function configureAutomaticYield() external; function configureAutomaticYieldOnBehalf(address contractAddress) external; function configureVoidYield() external; function configureVoidYieldOnBehalf(address contractAddress) external; function configureClaimableGas() external; function configureClaimableGasOnBehalf(address contractAddress) external; function configureVoidGas() external; function configureVoidGasOnBehalf(address contractAddress) external; function configureGovernor(address _governor) external; function configureGovernorOnBehalf(address _newGovernor, address contractAddress) external; // claim yield function claimYield(address contractAddress, address recipientOfYield, uint256 amount) external returns (uint256); function claimAllYield(address contractAddress, address recipientOfYield) external returns (uint256); // claim gas function claimAllGas(address contractAddress, address recipientOfGas) external returns (uint256); function claimGasAtMinClaimRate( address contractAddress, address recipientOfGas, uint256 minClaimRateBips ) external returns (uint256); function claimMaxGas(address contractAddress, address recipientOfGas) external returns (uint256); function claimGas( address contractAddress, address recipientOfGas, uint256 gasToClaim, uint256 gasSecondsToConsume ) external returns (uint256); // read functions function readClaimableYield(address contractAddress) external view returns (uint256); function readYieldConfiguration(address contractAddress) external view returns (uint8); function readGasParams( address contractAddress ) external view returns (uint256 etherSeconds, uint256 etherBalance, uint256 lastUpdated, GasMode); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; interface IBlastPoints { function configurePointsOperator(address operator) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; enum YieldMode { AUTOMATIC, VOID, CLAIMABLE } interface IERC20Rebasing { // changes the yield mode of the caller and update the balance // to reflect the configuration function configure(YieldMode) external returns (uint256); // "claimable" yield mode accounts can call this this claim their yield // to another address function claim(address recipient, uint256 amount) external returns (uint256); // read the claimable amount for an account function getClaimableAmount(address account) external view returns (uint256); }
// 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; 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; 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; 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 YoloLimit * @notice This contract permissionlessly hosts yolos with deposit limit on YOLO Games. * @author YOLO Games protocol team */ contract YoloLimit 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 = 1_000; /** * @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 maximum deposit amount per round in ETH. * * @dev Unlike valuePerEntry, this is not stored in each round's round struct. * So whenever this is updated, it will be applied to the current round. * as well. */ uint96 public maximumDepositAmountPerRound; /** * @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 A user's deposited amount in ETH in any given round. */ mapping(uint256 roundId => mapping(address depositor => uint256 amount)) public depositedAmount; /** * @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; event MaximumDepositAmountPerRoundUpdated(uint256 maximumDepositAmountPerRound); error ExceededMaximumDepositAmountPerRound(); /** * @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); _updateMaximumDepositAmountPerRound(0.1 ether); 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(); } _incrementUserDepositAmount(roundId, depositAmount); 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(); } _incrementUserDepositAmount(roundId, rolloverAmount); 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); } /** * @notice Updates the maximum deposit amount per round. Only callable by the owner. */ function updateMaximumDepositAmountPerRound(uint96 _maximumDepositAmountPerRound) external { _validateIsOwner(); _updateMaximumDepositAmountPerRound(_maximumDepositAmountPerRound); } /** * @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 _maximumDepositAmountPerRound The maximum deposit amount per round in ETH. */ function _updateMaximumDepositAmountPerRound(uint96 _maximumDepositAmountPerRound) private { if (_maximumDepositAmountPerRound == 0) { _revertWithInvalidValue(); } maximumDepositAmountPerRound = _maximumDepositAmountPerRound; emit MaximumDepositAmountPerRoundUpdated(_maximumDepositAmountPerRound); } /** * @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(2_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)); } _incrementUserDepositAmount(roundId, totalEntriesCount * round.valuePerEntry); 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 roundId The round ID. * @param depositAmount The deposit amount in ETH. */ function _incrementUserDepositAmount(uint256 roundId, uint256 depositAmount) private { if (depositedAmount[roundId][msg.sender] + depositAmount > maximumDepositAmountPerRound) { revert ExceededMaximumDepositAmountPerRound(); } depositedAmount[roundId][msg.sender] += depositAmount; } /** * @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() internal 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; } } }
{ "viaIR": true, "optimizer": { "enabled": true, "runs": 888888 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "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"},{"internalType":"address","name":"_ethYieldConfiguration","type":"address"},{"internalType":"address","name":"_usdbYieldConfiguration","type":"address"},{"internalType":"address","name":"_blastPoints","type":"address"},{"internalType":"address","name":"_blastPointsOperator","type":"address"}],"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":"ExceededMaximumDepositAmountPerRound","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":"uint256","name":"maximumDepositAmountPerRound","type":"uint256"}],"name":"MaximumDepositAmountPerRoundUpdated","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":[{"internalType":"address","name":"wethReceiver","type":"address"},{"internalType":"address","name":"usdbReceiver","type":"address"}],"name":"claim","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":[{"internalType":"uint256","name":"roundId","type":"uint256"},{"internalType":"address","name":"depositor","type":"address"}],"name":"depositedAmount","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","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":"maximumDepositAmountPerRound","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"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":"uint96","name":"_maximumDepositAmountPerRound","type":"uint96"}],"name":"updateMaximumDepositAmountPerRound","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
6101a0604052346200009e57620000236200001962000171565b9392909262000359565b604051615f90908162000d3a8239608051816106fe015260a051818181610e00015281816121280152615047015260c05181614bd9015260e05181614bff01526101005181614c7001526101205181614c2f015261014051818181612ce8015261509b01526101605181610abe01526101805181610b100152f35b5f80fd5b6001600160401b038111620000b657604052565b634e487b7160e01b5f52604160045260245ffd5b601f909101601f19168101906001600160401b03821190821017620000b657604052565b6040519061022082016001600160401b03811183821017620000b657604052565b51906001600160a01b03821682036200009e57565b519064ffffffffff821682036200009e57565b51906001600160601b03821682036200009e57565b519061ffff821682036200009e57565b51906001600160401b03821682036200009e57565b62006d2a9081380391826040519384926200018d8285620000ca565b8339810103916102a083126200009e576102208093126200009e57620002fc620001b6620000ee565b93620001c2836200010f565b8552620001d2602084016200010f565b6020860152620001e56040840162000124565b6040860152620001f86060840162000124565b60608601526200020b6080840162000137565b60808601526200021e60a084016200010f565b60a08601526200023160c084016200014c565b60c08601526200024460e084016200014c565b60e08601526101008084015190860152610120620002648185016200015c565b90860152610140620002788185016200010f565b908601526101606200028c8185016200010f565b90860152610180620002a08185016200010f565b908601526101a0620002b48185016200010f565b908601526101c0620002c88185016200010f565b908601526101e0620002dc81850162000124565b90860152610200620002f08185016200014c565b9086015282016200010f565b926200030c61024083016200010f565b926200032b6102806200032361026086016200010f565b94016200010f565b919493929190565b5f9103126200009e57565b6040513d5f823e3d90fd5b908160209103126200009e575190565b9392919362000368816200054a565b80516001600160a01b039283169190831691803b156200009e5760405163c8992e6160e01b815260026004820152600160248201526001600160a01b039390931660448401525f908390606490829084905af1918215620004d6576101c09262000533575b50018051909290620003f690620003ea906001600160a01b031681565b6001600160a01b031690565b604051631a33757d60e01b80825260026004830152966020928390839060249082905f905af1918215620004d657859262000511575b5060405197885260026004890152169581816024815f8b5af18015620004d657620004dc575b505016803b156200009e576040516336b91f2b60e01b81526001600160a01b039390931660048401525f908390602490829084905af1908115620004d657620004ae92620003ea92620004b8575b50516001600160a01b031690565b6101605261018052565b80620004c8620004cf92620000a2565b8062000333565b5f620004a0565b6200033e565b816200050092903d1062000509575b620004f78183620000ca565b81019062000349565b505f8062000452565b503d620004eb565b6200052b90843d86116200050957620004f78183620000ca565b505f6200042c565b80620004c86200054392620000a2565b5f620003cd565b6200071b620003ea610180610140938481016200057a62000571825160018060a01b031690565b60805260018055565b600380546001600160f81b0316600160f81b1790558151620005a5906001600160a01b03166200072a565b6020820151620005be906001600160a01b0316620007a0565b620005db620005d5606084015164ffffffffff1690565b62000850565b60a0820151620005f4906001600160a01b0316620008d1565b6200060e6200060860c084015161ffff1690565b62000934565b620006286200062260e084015161ffff1690565b62000991565b608082015162000641906001600160601b0316620009ee565b6101a08201516200065b906001600160a01b031662000a3e565b6200067862000672604084015164ffffffffff1690565b62000a8e565b61016082015162000692906001600160a01b031662000af3565b620006b0620006aa6101e084015164ffffffffff1690565b62000b43565b620006ba62000b9a565b6101c08201516001600160a01b031660a0526101008281015160c0529051620006ec906001600160a01b0316620003ea565b9052610120818101516001600160401b031660e05261020082015161ffff16905201516001600160a01b031690565b90526200072762000be0565b50565b6001600160a01b0381165f9081525f8051602062006d0a833981519152602052604090205460ff16156200075b5750565b6001600160a01b03165f8181525f8051602062006d0a83398151915260205260408120805460ff191660011790553391905f8051602062006cca8339815191528180a4565b6001600160a01b0381165f9081527fee57cd81e84075558e8fcc182a1f4393f91fc97f963a136e66b7f949a62f319f60205260409020547f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b9299060ff161562000806575050565b5f818152602081815260408083206001600160a01b03861684529091529020805460ff1916600117905533916001600160a01b0316905f8051602062006cca8339815191525f80a4565b64ffffffffff811690610e108211620008c4577fbdeccc4cf4c928bfff2005eee2fd4b91bb3d22035af62a93e35b1eedf853e3a39160209170ffffffffff0000000000000000000000006003549160601b169070ffffffffff000000000000000000000000191617600355604051908152a1565b63aa7feadc5f526004601cfd5b6001600160a01b038116908115620008c457600480546001600160601b031660609290921b6001600160601b0319169190911790556040519081527fc1b5345cce283376356748dc57f2dfa7120431d016fc7ca9ba641bc65f91411d90602090a1565b61ffff8116906109c48211620008c4576003805461ffff60881b191660889290921b61ffff60881b169190911790556040519081527fede4aee4284b8033b84c1aadcc51b229a4e46e6b42ab40092e237f07508b462690602090a1565b61ffff8116906127108211620008c4576003805461ffff60981b191660989290921b61ffff60981b169190911790556040519081527f2e38c85b973ddf3d7c0cbd813bddb9b63db96d86ff7b6ccce361777d674d813c90602090a1565b6001600160601b03168015620008c457600380546001600160601b031916821790556040519081527f988fd919afedb9b211cf201222b0091d485871857d14d2a87946e1ee390a17f490602090a1565b6001600160a01b03168015620008c457600580546001600160a01b031916821790556040519081527f2d5eba1cf3f9252b2aa813087328fc416c6c2ad0fb1417f9f5f78f08cb24cfdb90602090a1565b64ffffffffff81169060028210620008c4576003805464ffffffffff60d01b191660d09290921b64ffffffffff60d01b169190911790556040519081527f32e1033127c5a25fa4a87832fb767338db2bca3d4eba8f34be6d5a8f71e9227590602090a1565b6001600160a01b03168015620008c457600680546001600160a01b031916821790556040519081527fa75f06c1fcb711f11e4fe2a1e8b84e798cce8ea1c6d6db252abe31ebd836e21f90602090a1565b6006805464ffffffffff60a01b191660a083901b64ffffffffff60a01b1617905560405164ffffffffff90911681527ff020ff23e722cd62b0e67a05c051cc3dc4b4d0c48e01de57a0571ad6a180c35d90602090a1565b7fab9b0becdb6bda45e0cb0aedf05c920174daf5b035652783df65736347ec8b98602067016345785d8a00008060018060601b03196004541617600455604051908152a1565b6003805464ffffffffff60a81b1916600160a81b179081905560015f819052600860205291905f8051602062006cea83398151915260018101546001600160601b039060a01c1662000cdd57505060035460015f819052600860205260c882901c65ffffffffff0016605883901c67ffff0000000000001617175f8051602062006cea8339815191525560a081901b6001600160a01b0319167fad67d757c34507f157cacfa2e3153e9f260a2244f30428821be7be64587ac56055505b7ffbe046f0ca401af45e57af7a8efd3840294bfc077bf062f4b9919e2c028e161c6040518062000cd881906001602060408401938281520152565b0390a1565b5460901c64ffffffffff1660015f526008602052905f8051602062006cea83398151915290815490600182179362000d19575b50505562000c9d565b600192935064ffffffffff9060601c16420160401b1717905f8062000d1056fe60806040526004361015610011575f80fd5b5f3560e01c806301ffc9a714610344578063197a32431461033f5780631df47f801461033a5780631fe543e31461033557806320e672321461033057806321c0b3421461032b578063248a9ca31461032657806327ab6b68146103215780632f2ff15d1461031c578063311b8d5c1461031757806336566f061461031257806336568abe1461030d57806340e58ee5146103085780634245d5f014610303578063472f5b06146102fe5780635410d098146102f957806354854797146102f4578063553be400146102ef57806358fc096f146102ea5780635c975abb146102e55780635cb6dfff146102e057806361510d31146102db578063624ab3ac146102d657806365294500146102d15780636df1d48a146102cc578063709563e2146102c75780637c8b287c146102c25780637d33ca3f146102bd5780637d7c3c74146102b85780638f1327c0146102b3578063911c66b8146102ae57806391d14854146102a957806398753c46146102a45780639f5cfe031461029f578063a217fddf1461029a578063a5cbbd2314610295578063aa73b5ac14610290578063b12957f61461028b578063b2185bb114610286578063bbc492c014610281578063bcfdf2191461027c578063bfbf228414610277578063c66944ba14610272578063ca232b091461026d578063cb5305f314610268578063d0a2c33614610263578063d547741f1461025e578063ea8a1af014610259578063f4c8770e14610254578063f7cb789a1461024f5763fa2f0a8d1461024a575f80fd5b6137ac565b613767565b6136f7565b613641565b6135e4565b61348d565b613346565b612b89565b612af1565b612a5f565b612a16565b6129a3565b6128e3565b61286a565b612821565b6127a0565b612768565b612723565b6126e1565b612664565b6125c0565b612473565b611f99565b611ddd565b611cb7565b611c0e565b611b58565b611aa2565b6119fa565b6119a9565b611941565b611901565b6118bf565b61173b565b611631565b6115e0565b61155f565b611483565b61132e565b611246565b611119565b611083565b610f1c565b610d1b565b610ca0565b610a21565b61096a565b610684565b6104a3565b610440565b610377565b7fffffffff0000000000000000000000000000000000000000000000000000000081160361037357565b5f80fd5b346103735760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103735760207fffffffff000000000000000000000000000000000000000000000000000000006004356103d581610349565b167f7965db0b00000000000000000000000000000000000000000000000000000000811490811561040c575b506040519015158152f35b7f01ffc9a7000000000000000000000000000000000000000000000000000000009150145f610401565b5f91031261037357565b34610373575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037357602064ffffffffff60035460d01c16604051908152f35b73ffffffffffffffffffffffffffffffffffffffff81160361037357565b346103735760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610373576004356104de81610485565b6104e6613ebb565b73ffffffffffffffffffffffffffffffffffffffff811690811561056e577fc1b5345cce283376356748dc57f2dfa7120431d016fc7ca9ba641bc65f91411d916020916bffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000006004549260601b16911617600455604051908152a1005b63aa7feadc5f526004601cfd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b67ffffffffffffffff81116105bc57604052565b61057b565b60e0810190811067ffffffffffffffff8211176105bc57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176105bc57604052565b67ffffffffffffffff81116105bc5760051b60200190565b92916106418261061e565b9161064f60405193846105dd565b829481845260208094019160051b810192831161037357905b8282106106755750505050565b81358152908301908301610668565b346103735760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103735760043560243567ffffffffffffffff81116103735736602382011215610373576106e7903690602481600401359101610636565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016803303610933575061074261073b835f52600b60205260405f2090565b5460ff1690565b61074857005b61077861076e610760845f52600b60205260405f2090565b5460081c64ffffffffff1690565b64ffffffffff1690565b9061078b825f52600860205260405f2090565b906002610799835460ff1690565b6107a281612324565b146107aa575b005b6107bd906107b88484614d4b565b613b78565b51928360016107d581935f52600b60205260405f2090565b01556003808301918254906107e982613aa0565b925f5b8381106108ff575050506108e06107a8966108db6108ca61087a600361085e6002996108586108f79a60016108516108497fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6108ef9e0184613b85565b51809b613b1c565b01906154ca565b9061390e565b50015473ffffffffffffffffffffffffffffffffffffffff1690565b6108c360018a0191829073ffffffffffffffffffffffffffffffffffffffff167fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055565b5460a01c90565b6bffffffffffffffffffffffff1690565b613e74565b845460301c61ffff1690613e74565b612710900490565b910155614e67565b8061092261076e8461091287958b61390e565b50015460a81c64ffffffffff1690565b61092c8288613b85565b52016107ec565b604490604051907f1cf993f40000000000000000000000000000000000000000000000000000000082523360048301526024820152fd5b34610373575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610373576109a0613ebb565b7f67aa0e8084cf2c79566eed90861fb37a9bf4106afb0fd2ee5b3428b4a5767c7b60206003548060f81c15907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fff000000000000000000000000000000000000000000000000000000000000008360f81b16911617600355604051908152a1005b346103735760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037357600435610a5c81610485565b60243590610a6982610485565b610a71613ebb565b6040517fe12f3a61000000000000000000000000000000000000000000000000000000008082523060048301526020939092909173ffffffffffffffffffffffffffffffffffffffff91907f000000000000000000000000000000000000000000000000000000000000000083168682602481845afa908115610bd85787925f92610c81575b5081610bfa575b505060405194855250503060048401527f000000000000000000000000000000000000000000000000000000000000000016918381602481865afa908115610bd8575f91610bdd575b5080610b4f57005b6040517faad3ec9600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9290921660048301526024820152908290829060449082905f905af18015610bd857610bb257005b816107a892903d10610bd1575b610bc981836105dd565b8101906137ec565b503d610bbf565b6137fb565b610bf49150843d8611610bd157610bc981836105dd565b5f610b47565b6040517faad3ec9600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9490941660048501526024840191909152829060449082905f905af18015610bd857610c64575b848180610afe565b610c7a90853d8711610bd157610bc981836105dd565b505f610c5c565b610c99919250833d8511610bd157610bc981836105dd565b905f610af7565b346103735760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610373576004355f525f6020526020600160405f200154604051908152f35b9181601f840112156103735782359167ffffffffffffffff8311610373576020808501948460051b01011161037357565b34610373576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103735760043567ffffffffffffffff811161037357610d6b903690600401610cea565b90600192600260015414610ef2576002600155610d86613f00565b610d8e613806565b5f91610d9985613f1a565b5f5b858110610e595750507f573056d40bdb0e131a339ac518c08135633a29c4a83b7efb171c4f931fbf40d59450602081015180610e2a575b505080610df7575b50610deb6040519283923384613a73565b0390a16107a860018055565b610e24905a90337f00000000000000000000000000000000000000000000000000000000000000006142d1565b5f610dda565b610e4b610e52925173ffffffffffffffffffffffffffffffffffffffff1690565b33906141d8565b5f80610dd2565b80610e668892888861385c565b610e8f610e7c82355f52600860205260405f2090565b91610e8683613f2e565b858101906138a1565b610e9881613f1a565b60035f93015b818410610eaf575050505001610d9b565b90919297610ee8869189610ed9610ec78d888a6138fe565b35610ed3875482613f93565b8661390e565b50610ee381613fa8565b613fd7565b9801929190610e9e565b60046040517f1bbee726000000000000000000000000000000000000000000000000000000008152fd5b346103735760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037357602435600435610f5a82610485565b805f525f602052610f71600160405f2001546143f4565b805f525f60205260ff610fa58360405f209073ffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b541615610fae57005b805f525f602052610fe08260405f209073ffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b60017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082541617905573ffffffffffffffffffffffffffffffffffffffff339216907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d5f80a4005b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60209101126103735760043561ffff811681036103735790565b346103735761109136611048565b611099613ebb565b61ffff8116906109c4821161056e577fede4aee4284b8033b84c1aadcc51b229a4e46e6b42ab40092e237f07508b4626916020917fffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffff72ffff00000000000000000000000000000000006003549260881b16911617600355604051908152a1005b34610373575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103735761114f613ebb565b60025460ff8116156111e9575060025460ff8116156111bf577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166002557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6020604051338152a16107a861456d565b60046040517f6cd60201000000000000000000000000000000000000000000000000000000008152fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0060019161121561474d565b16176002557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a1005b346103735760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103735760243561128181610485565b3373ffffffffffffffffffffffffffffffffffffffff8216036112aa576107a890600435614603565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c6600000000000000000000000000000000006064820152fd5b34610373576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610373576004359061136a613ebb565b81156114385764ffffffffff60035460a81c16905f5b8381106113f4576107a87fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85857f0c4874e1a947afdb9c813baf258eec6a442b25531183f82046efc9760f640773604051806113ea85858360209093929193604081019481520152565b0390a10101614e67565b8060019184015f526008835261143260405f2060047fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b01611380565b63cbc4e0605f526004601cfd5b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60209101126103735760043564ffffffffff811681036103735790565b346103735761149136611445565b611499613ebb565b64ffffffffff811690610e10821161056e577fbdeccc4cf4c928bfff2005eee2fd4b91bb3d22035af62a93e35b1eedf853e3a3916020917fffffffffffffffffffffffffffffff0000000000ffffffffffffffffffffffff70ffffffffff0000000000000000000000006003549260601b16911617600355604051908152a1005b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6020910112610373576004356bffffffffffffffffffffffff811681036103735790565b34610373576bffffffffffffffffffffffff61157a3661151a565b611582613ebb565b16801561056e576020817f988fd919afedb9b211cf201222b0091d485871857d14d2a87946e1ee390a17f4927fffffffffffffffffffffffffffffffffffffffff0000000000000000000000006003541617600355604051908152a1005b34610373575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037357602073ffffffffffffffffffffffffffffffffffffffff60065416604051908152f35b346103735760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103735760043561166c81610485565b611674613ebb565b6002549073ffffffffffffffffffffffffffffffffffffffff8260081c166116dc5774ffffffffffffffffffffffffffffffffffffffff007fffffffffffffffffffffff0000000000000000000000000000000000000000ff9160081b169116176002555f80f35b63d6336f0d5f526004601cfd5b9060407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc83011261037357600435916024359067ffffffffffffffff82116103735761173791600401610cea565b9091565b611744366116e9565b600192919290600260015414610ef257600260015561176161474d565b80156118ba57611779835f52600860205260405f2090565b9361178385614783565b61178c856147cb565b5f61179683613aa0565b935f5b848110611823575050340361181e576117db7fa315167fc4200676e8597c5df065fafa8cecfeac15a8e2aded299a649e4a517593604051938493873386613b99565b0390a1611800825464ffffffffff90600385015491808260081c169160901c16614b39565b61180e575b6107a860018055565b61181791614b62565b5f80611805565b61056e565b80870190611839825f52600860205260405f2090565b9161184a6108ca8585015460a01c90565b9081156118a9575b61185c848261490e565b6118678389896138fe565b35906118738383613b1c565b61181e57816118979382889761188c84611891966149f7565b614ab5565b95613b6b565b936118a28289613b85565b5201611799565b90506118b48161482e565b90611852565b6146d8565b34610373575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037357602061ffff60035460981c16604051908152f35b34610373575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037357602060ff600254166040519015158152f35b346103735760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610373576004355f52600b602052606060405f206001815491015464ffffffffff6040519260ff81161515845260081c1660208301526040820152f35b34610373575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037357602073ffffffffffffffffffffffffffffffffffffffff60055416604051908152f35b34610373575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037357600260015414610ef2576002600155611a3f613f00565b64ffffffffff8060035460a81c16805f52600860205260405f2091611a6383613f51565b611a7281845460681c16613c0c565b164210611a9557611a8681611a8b93614da8565b614e67565b506107a860018055565b63f4c0ca6e5f526004601cfd5b346103735760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103735773ffffffffffffffffffffffffffffffffffffffff600435611af281610485565b611afa613ebb565b16801561056e576020817f2d5eba1cf3f9252b2aa813087328fc416c6c2ad0fb1417f9f5f78f08cb24cfdb927fffffffffffffffffffffffff00000000000000000000000000000000000000006005541617600555604051908152a1005b346103735760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103735773ffffffffffffffffffffffffffffffffffffffff600435611ba881610485565b611bb0613ebb565b16801561056e576020817fa75f06c1fcb711f11e4fe2a1e8b84e798cce8ea1c6d6db252abe31ebd836e21f927fffffffffffffffffffffffff00000000000000000000000000000000000000006006541617600655604051908152a1005b34610373575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037357602064ffffffffff60065460a01c16604051908152f35b8015150361037357565b60407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc820112610373576004359067ffffffffffffffff821161037357611ca691600401610cea565b9091602435611cb481611c53565b90565b3461037357611cc536611c5d565b5f92915f925f915b808310611d1b575050505f14611cfe5750611cea611cfa91614f8a565b6040519081529081906020820190565b0390f35b80821015611d11575050611cfa5f611cea565b611cfa9103611cea565b909194611d2986838561385c565b611d53611d3f82355f52600860205260405f2090565b91611d4983613f67565b60208101906138a1565b60038301908154915f5b828110611d835750505050506001916002611d7a92015490613b6b565b95019190611ccd565b611d8e8184876138fe565b3584811015611dd857611da1908361390e565b50805460ff16611db081612340565b15611dbf575b50600101611d5d565b6001919b6002611dd192015490613b6b565b9a90611db6565b613f9b565b611de636611c5d565b91600292600193600260015414610ef2576002600155611e04613f00565b611e0c613806565b915f955f9282611e1b88613f1a565b611f8e575b5f5b878110611efb5750505081611e79575b5050928360207ffbb3d671e318a7ebc6333ba95648c22dc746b01f141b5e81939d55d4664be29595015180610e2a57505080610df75750610deb6040519283923384613a73565b15611eb25790611eaa7ffbb3d671e318a7ebc6333ba95648c22dc746b01f141b5e81939d55d4664be2959592615079565b90935f611e32565b80611ebf611ec692615015565b3490613c51565b848111611ef6577ffbb3d671e318a7ebc6333ba95648c22dc746b01f141b5e81939d55d4664be295940390611eaa565b6146e5565b611f0681898961385c565b611f2f611f1c82355f52600860205260405f2090565b91611f2683613f67565b611d4983614fe6565b90611f3982613f1a565b5f91600384015b818410611f655750505050905f611f5d8486940197885490613b6b565b965501611e22565b9091929c611f8488918f611f7e610ec78f92888a6138fe565b50613fd7565b9d01929190611f40565b3415611e205761056e565b346103735760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037357600480359060243567ffffffffffffffff811161037357611fed903690600401610cea565b9160443590611ffb82611c53565b6002916001600260015414610ef257600260015561201761474d565b5f935f9361202488613f1a565b5f5b888110612182575050505081612152575b505061204b845f52600860205260405f2090565b61205481614783565b61205e818661490e565b612067816147cb565b6120786108ca600183015460a01c90565b946120838684613b1c565b80612113575b5085831061181e576120cb837fecd5c5544dcd4a5344389c360ff979c215f25290177e786ca2c407e58a95b88a976120c4610deb96856149f7565b8385614ab5565b91816120ef825464ffffffffff90600385015491808260081c169160901c16614b39565b612103575b50506040519485943386613c5e565b61210c91614b62565b5f816120f4565b928361214c91612121613f00565b03935a90337f00000000000000000000000000000000000000000000000000000000000000006142d1565b5f612089565b156121675761216090615079565b5f80612037565b908181105f036146e5578161217d910391615015565b612160565b61218d818a8a61385c565b6121a081355f52600860205260405f2090565b906121ac825460ff1690565b916121b683612324565b6003918284106122f2576121e2906121cd85612324565b8385146122d2575b60208195939501906138a1565b90926121ed82613f1a565b805f950192878114935b83871061220c57505050505050508301612026565b9091929394959c6122336122218f878a6138fe565b3561222d845482613f93565b8361390e565b5061223d816151a3565b805460ff1661224b81612340565b6122cd578b918b6122b2928961226088612324565b6122bf575b6122aa888201740100000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff825416179055565b015490613b6b565b9d019594939291906121f7565b6122c881613fa8565b612265565b6146f2565b6122db83614fe6565b5f6122eb8985019c8d5490613b6b565b9b556121d5565b613f44565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b6005111561232e57565b6122f7565b90600582101561232e5752565b6003111561232e57565b9698939590979492919260206101606101409961236a818c81019d612333565b829a64ffffffffff8098168483015261ffff6040971660408301528760609b166060830152876080951660808301528760a0961660a083015260c09873ffffffffffffffffffffffffffffffffffffffff9e8f1660c08401526bffffffffffffffffffffffff60e09b1660e08401526101008301526101208201528d51809c52019b01995f975b8a89106124075750505050505050505050505090565b909192939495969798999a9b8a896001928f8b8b9151805161242881612340565b8452808601518916868501528b8101518c85015287810151888501528981015189168a8501528a81015115158b8501520151168b820152019d019b9a990197969594939291906123f1565b346103735760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610373576004355f8181526008602052604090208054603081901c61ffff16929091611cfa91906124d7905460401c64ffffffffff1690565b906124fb6124ed825f52600860205260405f2090565b5460681c64ffffffffff1690565b61251e612510835f52600860205260405f2090565b5460901c64ffffffffff1690565b6125506001612535855f52600860205260405f2090565b015473ffffffffffffffffffffffffffffffffffffffff1690565b906125706001612568865f52600860205260405f2090565b015460a01c90565b926125a4600361259e600261258d895f52600860205260405f2090565b0154975f52600860205260405f2090565b01613c9d565b95604051998960ff64ffffffffff8d9c60081c1691168b61234a565b34610373576125ce36611445565b6125d6613ebb565b64ffffffffff8116906002821061056e577f32e1033127c5a25fa4a87832fb767338db2bca3d4eba8f34be6d5a8f71e92275916020917fff0000000000ffffffffffffffffffffffffffffffffffffffffffffffffffff7effffffffff00000000000000000000000000000000000000000000000000006003549260d01b16911617600355604051908152a1005b346103735760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037357602060ff6126d56024356126a681610485565b6004355f525f845260405f209073ffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b54166040519015158152f35b34610373575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037357602061ffff60035460881c16604051908152f35b34610373575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037357602064ffffffffff60035460a81c16604051908152f35b34610373575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103735760206040515f8152f35b34610373576bffffffffffffffffffffffff6127bb3661151a565b6127c3613ebb565b16801561056e576020817fab9b0becdb6bda45e0cb0aedf05c920174daf5b035652783df65736347ec8b98927fffffffffffffffffffffffffffffffffffffffff0000000000000000000000006004541617600455604051908152a1005b34610373575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103735760206bffffffffffffffffffffffff60035416604051908152f35b346103735760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103735760206128da6024356128aa81610485565b6004355f526009835260405f209073ffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b54604051908152f35b34610373575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037357600260015414610ef257600260015561292861474d565b64ffffffffff8060035460a81c16805f52600860205260405f209161294c83613f7d565b825490808260901c169161297161296d6003870154848460081c1686614b39565b1590565b612980575b6118058486614b62565b60401c16421061299e57600211612999575f8080612976565b6146ff565b6136e0565b346103735760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103735773ffffffffffffffffffffffffffffffffffffffff6004356129f381610485565b165f52600c60205260405f206024355f52602052602060405f2054604051908152f35b34610373575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103735760206bffffffffffffffffffffffff60045416604051908152f35b34610373577ff020ff23e722cd62b0e67a05c051cc3dc4b4d0c48e01de57a0571ad6a180c35d6020612a9036611445565b612a98613ebb565b6006547fffffffffffffff0000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000008360a01b1691161760065564ffffffffff60405191168152a1005b3461037357612aff36611048565b612b07613ebb565b61ffff811690612710821161056e577f2e38c85b973ddf3d7c0cbd813bddb9b63db96d86ff7b6ccce361777d674d813c916020917fffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffff74ffff000000000000000000000000000000000000006003549260981b16911617600355604051908152a1005b612b92366116e9565b91600260015414610ef2576002600155612baa61474d565b612bbc815f52600860205260405f2090565b612bc581614783565b612bcf818361490e565b612bd8816147cb565b6003810154935f905f94612bfc612bf7865f52600860205260405f2090565b613b58565b92346132b45782156118ba575b82612cb7575b505050612c81857f73a19dd210f1a7f902193214c0ee91dd35ee5b4d920cba8d519eca65a7b488ca968593612c5d612c57612c516108ca60018a015460a01c90565b8a613e74565b866149f7565b55835464ffffffffff808260901c1691612c7783856156b4565b60081c1690614b39565b612ca7575b50506040805133815260208101929092528101919091528060608101610deb565b612cb091614b62565b5f81612c86565b9190612cc2826151c0565b925f905b838210612dab575050505073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016803b1561037357612d505f929183926040519485809481937f0ca8e8a800000000000000000000000000000000000000000000000000000000835230903390600485016152d4565b03925af1958615610bd857808593612c81937f73a19dd210f1a7f902193214c0ee91dd35ee5b4d920cba8d519eca65a7b488ca99612d92575b50935096612c0f565b80612d9f612da5926105a8565b80610436565b5f612d89565b93979298612dbe828b859a949995615257565b94612dcb60208701613db7565b946001612e2d612dda89615297565b604051612e1c81612df060208201948d86613dc1565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018352826105dd565b5190205f52600760205260405f2090565b54036132af57612e6c84612e5f8873ffffffffffffffffffffffffffffffffffffffff165f52600c60205260405f2090565b905f5260205260405f2090565b546002612e7889615297565b612e8181612340565b0361306057801561301e575b612eae90612ea86108ca6001899e959798969e015460a01c90565b90613eb1565b93612eb885615756565b612ecf612ec860408a018a6138a1565b9050613aa0565b9a5f945b612ee060408b018b6138a1565b9050861015612f8a578c83808d898b98968f9a988e612f008c859a613b6b565b9b612f0a9361576a565b9960408101612f18916138a1565b612f2292916138fe565b3591612f36915f5260205f209060021b0190565b3379ffffffffff00000000000000000000000000000000000000000060a88b901b16176003820155600260088e901b1781556001015560010196612f7991613b85565b600190526001019491939092612ed3565b9c98613003929e965060019550612fca612feb92989c959d9499612fae878d613b85565b519073ffffffffffffffffffffffffffffffffffffffff169052565b612fe16020612fd9878d613b85565b510160019052565b60408101906138a1565b91906040612ff9868c613b85565b5101923691610636565b905260606130118389613b85565b5101525b01909291612cc6565b50612eae61302b88615808565b8061305887612e5f8b73ffffffffffffffffffffffffffffffffffffffff165f52600c60205260405f2090565b559050612e8d565b60016130768994979b959e969c98939d99615297565b61307f81612340565b14613090575b505050600190613015565b919a829c939c95919515613270575b6130b66130af60408e018e6138a1565b3691610636565b600181510361326b576130cb6130d391613b78565b518094613e74565b6040517f313ce56700000000000000000000000000000000000000000000000000000000815260208160048173ffffffffffffffffffffffffffffffffffffffff8c165afa8015610bd8576108ca60016131418f9495612ea8612ea89561314a985f9161323c575b50613ea0565b93015460a01c90565b9b6131548d615756565b6060918d8383013511613237578d8f8b88958f958c6131738585613b85565b5173ffffffffffffffffffffffffffffffffffffffff90911690526131988484613b85565b516020015f9052604081016131ac916138a1565b936131b79193613b85565b51019136906131c592610636565b90526131d091613b6b565b9c6131da9361576a565b936131ee83895f5260205f209060021b0190565b3379ffffffffff00000000000000000000000000000000000000000060a888901b1617600382015591600283015561322b919060081b6001179055565b600101985f8080613085565b61470c565b61325e915060203d602011613264575b61325681836105dd565b810190613e87565b5f61313b565b503d61324c565b613f21565b915061327b85615446565b91826132a98c612e5f8973ffffffffffffffffffffffffffffffffffffffff165f52600c60205260405f2090565b5561309f565b615439565b5094506132c86108ca600185015460a01c90565b6132d28134613b1c565b61181e576132e09034613eb1565b9460016132ee8789876156ea565b9761333561330582875f5260205f209060021b0190565b3379ffffffffff00000000000000000000000000000000000000000060a88d901b16176003820155349060020155565b0196612c09565b6003111561037357565b346103735760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103735760043567ffffffffffffffff811161037357613395903690600401610cea565b602435916133a28361333c565b604435926133af84611c53565b6133b76153f4565b6133c081612340565b80156132af575f5b83811061340757507f14f4f9b9a2d50cb168899c4825e24b7ffdc472b1dca88ddad74a834f7b62470b936134029160405194859485613e02565b0390a1005b600190851561348757815b6134806134286134238489896138fe565b613db7565b60ff6040519361346d856134418a602083019687613dc1565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018752866105dd565b16925190205f52600760205260405f2090565b55016133c8565b5f613412565b34610373577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60408136011261037357600435906024359067ffffffffffffffff82116103735760a09082360301126103735773ffffffffffffffffffffffffffffffffffffffff91602061355e61350760248501613db7565b9361353484612e5f8773ffffffffffffffffffffffffffffffffffffffff165f52600c60205260405f2090565b549081156135ca575b6135518160446135579301906004016138a1565b906138f5565b3590613e74565b926004604051809681937f313ce567000000000000000000000000000000000000000000000000000000008352165afa928315610bd8576108ca60016125686135bb611cea96612ea8611cfa99612ea8975f9161323c5750613ea0565b945f52600860205260405f2090565b90506135576135516135db87615446565b9291505061353d565b346103735760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610373576107a860243560043561362582610485565b805f525f60205261363c600160405f2001546143f4565b614603565b34610373575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037357600260015414610ef2576002600155613686613f00565b64ffffffffff8060035460a81c16805f52600860205260405f20916136aa83613f7d565b825490808260401c1680159081156136ed575b506136e05760019160901c16116136db57611a8681611a8b93614da8565b614719565b63f9ad93f55f526004601cfd5b905042105f6136bd565b346103735760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103735760206128da60243561373781610485565b6004355f52600a835260405f209073ffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b34610373575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037357602064ffffffffff60035460601c16604051908152f35b34610373575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037357602060035460f81c6040519015158152f35b90816020910312610373575190565b6040513d5f823e3d90fd5b604051906040820182811067ffffffffffffffff8211176105bc576040525f6020838281520152565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b919081101561389c5760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc181360301821215610373570190565b61382f565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610373570180359067ffffffffffffffff821161037357602001918160051b3603831361037357565b901561389c5790565b919081101561389c5760051b0190565b805482101561389c575f5260205f209060021b01905f90565b90918281527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83116103735760209260051b809284830137010190565b908290808452602080940193600592818360051b82010195855f925b85841061399257505050505050505090565b90919293949596977fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082820301845288357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc18436030181121561037357830160409080358352878101357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18236030181121561037357019087823592019267ffffffffffffffff831161037357828b1b360384136103735760019389938383869586613a619601520191613927565b9a019401940192969594939190613980565b60409073ffffffffffffffffffffffffffffffffffffffff611cb495931681528160208201520191613964565b90613aaa8261061e565b613ab760405191826105dd565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0613ae5829461061e565b0190602036910137565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b8115613b26570690565b613aef565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b9060038201809211613b6657565b613b2b565b91908201809211613b6657565b80511561389c5760200190565b805182101561389c5760209160051b010190565b92909373ffffffffffffffffffffffffffffffffffffffff613bd293951684526020946020850152608060408501526080840191613927565b906060818303910152602080845192838152019301915f5b828110613bf8575050505090565b835185529381019392810192600101613bea565b9062015f9064ffffffffff80931601918211613b6657565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8201918211613b6657565b91908203918211613b6657565b9160609373ffffffffffffffffffffffffffffffffffffffff613c939398979698168452608060208501526080840191613964565b9460408201520152565b908154613ca98161061e565b92604093613cba60405191826105dd565b82815280946020809201925f5260205f20905f935b858510613cde57505050505050565b6004846001928451613cef816105c1565b613da964ffffffffff8854613d9560ff808316613d0b81612340565b8652613d4973ffffffffffffffffffffffffffffffffffffffff809460081c168988019073ffffffffffffffffffffffffffffffffffffffff169052565b898c01548b87015260028c01546060870152613d8560038d0154938416608088019073ffffffffffffffffffffffffffffffffffffffff169052565b60a083811c909116151590860152565b60a81c1660c083019064ffffffffff169052565b815201930194019391613ccf565b35611cb481610485565b90917fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060159360601b168252613df681612340565b60f81b60148201520190565b92949391806060850160608652526080840191905f5b818110613e3c575050509060409194613e3081612340565b60208401521515910152565b90919260019073ffffffffffffffffffffffffffffffffffffffff8535613e6281610485565b16815260209081019401929101613e18565b81810292918115918404141715613b6657565b90816020910312610373575160ff811681036103735790565b60ff16604d8111613b6657600a0a90565b8115613b26570490565b335f9081527fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5602052604090205460ff1615613ef357565b6330cd74715f526004601cfd5b60035460f81c15613f0d57565b63010a265a5f526004601cfd5b15613f2157565b63947d5a845f526004601cfd5b5460ff16600581101561232e57600403613f4457565b63f525e3205f526004601cfd5b5460ff16600581101561232e57600203613f4457565b5460ff16600581101561232e57600303613f4457565b5460ff16600581101561232e57600103613f4457565b1015613f9b57565b6363df81715f526004601cfd5b6003015473ffffffffffffffffffffffffffffffffffffffff163303613fca57565b633cc50b455f526004601cfd5b90613fe1826151a3565b61402760038301740100000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff825416179055565b815460ff811661403681612340565b8061404b5750505060020154611cb491613b6b565b61405781949394612340565b600281036140915750508054611cb4925060019060081c73ffffffffffffffffffffffffffffffffffffffff169101549033903090615567565b8061409d600192612340565b146140a9575b50505090565b73ffffffffffffffffffffffffffffffffffffffff809160081c166140e2845173ffffffffffffffffffffffffffffffffffffffff1690565b918216810361410c575050602060026141019201549201918251613b6b565b90525b5f80806140a3565b61413f9084602060029594960195865180614148575b50509073ffffffffffffffffffffffffffffffffffffffff169052565b01549052614104565b6141539133906141d8565b5f80614122565b67ffffffffffffffff81116105bc57601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b3d156141be573d906141a58261415a565b916141b360405193846105dd565b82523d5f602084013e565b606090565b908160209103126103735751611cb481611c53565b919091803b156142a7576040517fa9059cbb000000000000000000000000000000000000000000000000000000006020820190815273ffffffffffffffffffffffffffffffffffffffff909416602482015260448101929092525f92839283906142458160648101612df0565b51925af1614251614194565b901561427d57805180614262575050565b8160208061296d9361427795010191016141c3565b61427d57565b60046040517ff1568f95000000000000000000000000000000000000000000000000000000008152fd5b60046040517f09ee12d5000000000000000000000000000000000000000000000000000000008152fd5b9091925f80808087876142e396f11590565b6142ec57505050565b73ffffffffffffffffffffffffffffffffffffffff1691823b1561037357604051927fd0e30db00000000000000000000000000000000000000000000000000000000084525f8460048185855af1928315610bd8576143a7946020946143e1575b505f6040518096819582947fa9059cbb000000000000000000000000000000000000000000000000000000008452600484016020909392919373ffffffffffffffffffffffffffffffffffffffff60408201951681520152565b03925af18015610bd8576143b9575b50565b6143b69060203d6020116143da575b6143d281836105dd565b8101906141c3565b503d6143c8565b80612d9f6143ee926105a8565b5f61434d565b805f525f60205260ff6144283360405f209073ffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b5416156144325750565b339061443c615a86565b91603061444884613b78565b53607861445484615ab3565b5360295b6001811161451f5761451b6144c06144e986612df06144808861447b8915615aff565b615b64565b6144ba6040519586946144ba602087016017907f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081520190565b90615649565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000815260110190565b6040519182917f08c379a0000000000000000000000000000000000000000000000000000000008352600483016156a3565b0390fd5b90600f811690601082101561389c577f3031323334353637383961626364656600000000000000000000000000000000614568921a61455e8487615ac3565b5360041c91615ad4565b614458565b64ffffffffff60035460a81c165f5b600181106145be57506143b6907f0c4874e1a947afdb9c813baf258eec6a442b25531183f82046efc9760f6407736040805183815260016020820152a1614e67565b8060019183015f5260086020526145fd60405f2060047fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b0161457c565b805f525f60205260ff6146378360405f209073ffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b5416614641575050565b805f525f6020526146738260405f209073ffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00815416905573ffffffffffffffffffffffffffffffffffffffff339216907ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b5f80a4565b63a95231d55f526004601cfd5b630134f2785f526004601cfd5b63a1e9dd9d5f526004601cfd5b637e439aed5f526004601cfd5b63f48cb8a05f526004601cfd5b637cd9dd6a5f526004601cfd5b63f90121325f526004601cfd5b63c11f59765f526004601cfd5b630da5618b5f526004601cfd5b60ff6002541661475957565b60046040517f1309a563000000000000000000000000000000000000000000000000000000008152fd5b5460ff8116600581101561232e57600114908115916147a4575b50613f4457565b60401c64ffffffffff168015159150816147c0575b505f61479d565b90504210155f6147b9565b805464ffffffffff808260401c16156147e357505050565b60035460601c164201804211613b66576cffffffffff00000000000000007fffffffffffffffffffffffffffffffffffffff0000000000ffffffffffffffff9160401b169116179055565b9060035460017fffffffffffffffffffffffff00000000000000000000000000000000000000006148766bffffffffffffffffffffffff8416955f52600860205260405f2090565b9267ffff0000000000008160581c1665ffffffffff008260c81c1617845560a01b16910155565b9060035460017fffffffffffffffffffffffff00000000000000000000000000000000000000006148e56bffffffffffffffffffffffff8416955f52600860205260405f2090565b928267ffff0000000000008260581c1665ffffffffff008360c81c161717845560a01b16910155565b805f52600960205261494060405f203373ffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b54908115614983575b600192505f526009602052016149803360405f209073ffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b55565b82549264ffffffffff93848160901c16948160081c1685146149ea577fffffffffffffffffff0000000000ffffffffffffffffffffffffffffffffffff16600194850160901b76ffffffffff00000000000000000000000000000000000016179055614949565b63b53a57db5f526004601cfd5b805f52600a602052614a2960405f203373ffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b54828101809111613b66576bffffffffffffffffffffffff6004541610614a8b575f52600a602052614a7c3360405f209073ffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b8054918201809211613b665755565b60046040517f8369f344000000000000000000000000000000000000000000000000000000008152fd5b90919392938015613b26578404936003820154916001830193614b01614af2888664ffffffffff95614aed87825460901c168b6156b4565b6156ea565b915f52600860205260405f2090565b9360038501809511613b6657600292614b26614b3492875f5260205f209060021b0190565b921660a81b33176003830155565b015555565b9190821091821592614b4a57505090565b600110915081614b58575090565b6103e89150101590565b614bb190614b708382614e0a565b80547fffffffffffffffffffffffffffff0000000000ffffffffffffffffffffffffff164260681b71ffffffffff0000000000000000000000000016179055565b6040517f5d3b1d300000000000000000000000000000000000000000000000000000000081527f000000000000000000000000000000000000000000000000000000000000000060048201527f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1660248201527f000000000000000000000000000000000000000000000000000000000000000061ffff166044820152622625a060648201526001608482015260208160a4815f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff165af1908115610bd8575f91614d2c575b50614ccb61073b825f52600b60205260405f2090565b614d27577f3d94fecedaa4f90b8bd459797adb95f5bb11426025c5541390d9ccc1ad1b60a191815f52600b60205260405f208160081b6001179055614d226040519283928360209093929193604081019481520152565b0390a1565b614726565b614d45915060203d602011610bd157610bc981836105dd565b5f614cb5565b7ffbe046f0ca401af45e57af7a8efd3840294bfc077bf062f4b9919e2c028e161c9160409160037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055815190815260036020820152a1565b7ffbe046f0ca401af45e57af7a8efd3840294bfc077bf062f4b9919e2c028e161c91614dfb60409260047fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b815190815260046020820152a1565b7ffbe046f0ca401af45e57af7a8efd3840294bfc077bf062f4b9919e2c028e161c9160409160027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055815190815260026020820152a1565b600101906003547fffffffffffff0000000000ffffffffffffffffffffffffffffffffffffffffff79ffffffffff0000000000000000000000000000000000000000008460a81b1691161780600355614ec8835f52600860205260405f2090565b6bffffffffffffffffffffffff614ee3600183015460a01c90565b16614f2e575050614ef38261489d565b505b60408051838152600160208201527ffbe046f0ca401af45e57af7a8efd3840294bfc077bf062f4b9919e2c028e161c9181908101614d22565b54614f429060901c64ffffffffff1661076e565b90614f55845f52600860205260405f2090565b908154906001821793614f6b575b505055614ef5565b600192935064ffffffffff9060601c16420160401b1717905f80614f63565b670de0b6b3a76400009080820291820403613b6657614fb39061ffff60035460981c1690613e74565b614fd773ffffffffffffffffffffffffffffffffffffffff60025460081c16615446565b8015613b265761271091040490565b6001015473ffffffffffffffffffffffffffffffffffffffff16330361500857565b63618c72425f526004601cfd5b60407fa0c67dacab0c86ad0a872c2ed3fa9deb08f80f4f0543d481f2fac9ee41d026919161506b60045460601c825a917f00000000000000000000000000000000000000000000000000000000000000006142d1565b81519081525f6020820152a1565b61508290614f8a565b73ffffffffffffffffffffffffffffffffffffffff90817f0000000000000000000000000000000000000000000000000000000000000000169160025460081c1660045460601c833b156103735760845f928360405196879485937fda3e8ce4000000000000000000000000000000000000000000000000000000008552600485015233602485015260448401528660648401525af1918215610bd8577fa0c67dacab0c86ad0a872c2ed3fa9deb08f80f4f0543d481f2fac9ee41d0269192615190575b5060025460081c73ffffffffffffffffffffffffffffffffffffffff166040805192835273ffffffffffffffffffffffffffffffffffffffff909116602083015281908101614d22565b80612d9f61519d926105a8565b5f615146565b6003015460a01c60ff166151b357565b636507689f5f526004601cfd5b906151ca8261061e565b60406151d960405192836105dd565b8382527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0615207839561061e565b01905f5b8281106152185750505050565b815190608082019180831067ffffffffffffffff8411176105bc5760209284525f8152825f81830152606080868401528083015282870101520161520b565b919081101561389c5760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6181360301821215610373570190565b35611cb48161333c565b9081518082526020808093019301915f5b8281106152c0575050505090565b8351855293810193928101926001016152b2565b93919392909260609460608201606083528551809152608090608084019760808260051b860101986020809901935f925b848410615359575050505050509061533b604092615357959683019073ffffffffffffffffffffffffffffffffffffffff169052565b019073ffffffffffffffffffffffffffffffffffffffff169052565b565b90919293949a8a806153e4838f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff808d60019703018952519073ffffffffffffffffffffffffffffffffffffffff8251168152838201516153b881612340565b84820152866153d460408a81860151918501528a8401906152a1565b92015190878184039101526152a1565b9d01940194019294939190615305565b335f9081527fee57cd81e84075558e8fcc182a1f4393f91fc97f963a136e66b7f949a62f319f602052604090205460ff161561542c57565b637c214f045f526004601cfd5b63c1ab6dc15f526004601cfd5b602073ffffffffffffffffffffffffffffffffffffffff604481600554169360405194859384927fe3cae776000000000000000000000000000000000000000000000000000000008452166004830152610e1060248301525afa908115610bd8575f916154b1575090565b611cb4915060203d602011610bd157610bc981836105dd565b8051918215615560575f925b80841061553257508215159182615514575b505015611cb4577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b61552991925061552384613c24565b90613b85565b51145f806154e8565b61553c8185615a71565b90826155488386613b85565b51111561555557506154d6565b9350600101926154d6565b5050505f90565b909192813b156142a7576040519260208401947f23b872dd00000000000000000000000000000000000000000000000000000000865273ffffffffffffffffffffffffffffffffffffffff809216602486015216604484015260648301526064825260a082019282841067ffffffffffffffff8511176105bc575f809493819460405251925af16155f6614194565b50156155fe57565b60046040517fe0f5c508000000000000000000000000000000000000000000000000000000008152fd5b5f5b8381106156395750505f910152565b818101518382015260200161562a565b9061565c60209282815194859201615628565b0190565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f60209361569c81518092818752878088019101615628565b0116010190565b906020611cb4928181520190615660565b6103e8908181116156dd57146156c75750565b6001146156d057565b63ae24220e5f526004601cfd5b6327e6fcc75f526004601cfd5b91906156f582615756565b80615707575064ffffffffff91501690565b600392837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6157389301910161390e565b5064ffffffffff928391015460a81c16908101809111613b66571690565b1561575d57565b63f91214385f526004601cfd5b64ffffffffff9390841692831561578a575050821601908111613b665790565b90919250611cb493506156ea565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610373570180359067ffffffffffffffff82116103735760200191813603831361037357565b9190826040910312610373576020823561580281610485565b92013590565b9060808201357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81833603018112156103735782019160208091013561584c81610485565b6040840135934285118015615a49575b615a445760405191826158ca858201928360805f9193929373ffffffffffffffffffffffffffffffffffffffff60a08201957f60d14eec5d309c7bcbba8f8779f8070820b882731ce8afd4d9282a327dfe6ede835260016020840152610e1060408401521660608201520152565b03926158fc7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0948581018352826105dd565b5190209080358203615a3f57615a2a846159ec6159f8615a2f9673ffffffffffffffffffffffffffffffffffffffff9a615a37998701976159af61594a6159438b8b615798565b3691615c01565b878151910120926159a36040519384928a8401964692889094939260809260a08301967f8c01f2233cc36f533c3fbfd8037c653a0326c46e0dc25bff9aea020c1a72a05484526020840152604083015260608201520152565b038481018352826105dd565b5190209360405193849182019586603c917f19457468657265756d205369676e6564204d6573736167653a0a3332000000008252601c8201520190565b039081018352826105dd565b51902060065473ffffffffffffffffffffffffffffffffffffffff16615a246159436060860186615798565b91615c63565b615798565b8101906157e9565b92166132af57565b614740565b614733565b50615a6a615a6461076e60065464ffffffffff9060a01c1690565b86613b6b565b421161585c565b90808216911860011c8101809111613b665790565b604051906060820182811067ffffffffffffffff8211176105bc57604052602a8252604082602036910137565b80516001101561389c5760210190565b90815181101561389c570160200190565b8015613b66577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b15615b0657565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602060248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152fd5b604051906080820182811067ffffffffffffffff8211176105bc576040526042825260603660208401376030615b9983613b78565b536078615ba583615ab3565b536041905b60018211615bbd57611cb4915015615aff565b600f811690601082101561389c577f3031323334353637383961626364656600000000000000000000000000000000615bfb921a61455e8486615ac3565b90615baa565b929192615c0d8261415a565b91615c1b60405193846105dd565b829481845281830111610373578281602093845f960137010152565b908160209103126103735751611cb481610349565b604090611cb4939281528160208201520190615660565b91813b615cbd57615c749192615da4565b73ffffffffffffffffffffffffffffffffffffffff9081169116146153575760046040517fd1085d1b000000000000000000000000000000000000000000000000000000008152fd5b615d1073ffffffffffffffffffffffffffffffffffffffff926020926040519485809481937f1626ba7e00000000000000000000000000000000000000000000000000000000998a845260048401615c4c565b0392165afa8015610bd8577fffffffff00000000000000000000000000000000000000000000000000000000915f91615d75575b5016146153575760046040517ff6cd0e2f000000000000000000000000000000000000000000000000000000008152fd5b615d97915060203d602011615d9d575b615d8f81836105dd565b810190615c37565b5f615d44565b503d615d85565b815160418103615ee45750602082015191606060408201519101515f1a925b7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08211615eba5760ff8416601b8114159081615eae575b50615e7a576040805193845260ff949094166020808501919091529383015260608201525f8080529060809060015afa15610bd8575f519073ffffffffffffffffffffffffffffffffffffffff821615615e5057565b60046040517ff05a20c7000000000000000000000000000000000000000000000000000000008152fd5b6040517f417893a400000000000000000000000000000000000000000000000000000000815260ff85166004820152602490fd5b601c915014155f615dfa565b60046040517fc1851252000000000000000000000000000000000000000000000000000000008152fd5b60408103615f27575060406020830151920151601b7f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82169160ff1c0192615dc3565b6040517fd42b4bbd0000000000000000000000000000000000000000000000000000000081526004810191909152602490fdfea2646970667358221220c87ac4716d5663a44d1771fe149e28db2dbd3ac53e5cb91c2bc779d5375c852564736f6c634300081700332f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0dad67d757c34507f157cacfa2e3153e9f260a2244f30428821be7be64587ac55fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5000000000000000000000000fb03340fdb69024c6579b35170f1b3c0d7d672420000000000000000000000002c64e6ee1dd9fc2a0db6a6b1aa2c3f163c7a2c7800000000000000000000000000000000000000000000000000000000000003e8000000000000000000000000000000000000000000000000000000000000007800000000000000000000000000000000000000000000000000038d7ea4c680000000000000000000000000006b86ff7863e27d1c8ccf05df9cb03b8efaa52125000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000013880000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000095c68c52bb12a43069973fdcd88e4e93d2142f10000000000000000000000000aeb1d03929bf87f69888f381e73fbf75753d75af00000000000000000000000000000000007fe8d7666bb0da2a5d13f72b8dabab0000000000000000000000009c9d8c8ee91f21004a40c4664d49cc1b9dfa69f90000000000000000000000004300000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000005a0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000430000000000000000000000000000000000000200000000000000000000000043000000000000000000000000000000000000030000000000000000000000002536fe9ab3f511540f2f9e2ec2a805005c3dd8000000000000000000000000004066b9bd584b5fa88897194dabe3a37883ac35f7
Deployed Bytecode
0x60806040526004361015610011575f80fd5b5f3560e01c806301ffc9a714610344578063197a32431461033f5780631df47f801461033a5780631fe543e31461033557806320e672321461033057806321c0b3421461032b578063248a9ca31461032657806327ab6b68146103215780632f2ff15d1461031c578063311b8d5c1461031757806336566f061461031257806336568abe1461030d57806340e58ee5146103085780634245d5f014610303578063472f5b06146102fe5780635410d098146102f957806354854797146102f4578063553be400146102ef57806358fc096f146102ea5780635c975abb146102e55780635cb6dfff146102e057806361510d31146102db578063624ab3ac146102d657806365294500146102d15780636df1d48a146102cc578063709563e2146102c75780637c8b287c146102c25780637d33ca3f146102bd5780637d7c3c74146102b85780638f1327c0146102b3578063911c66b8146102ae57806391d14854146102a957806398753c46146102a45780639f5cfe031461029f578063a217fddf1461029a578063a5cbbd2314610295578063aa73b5ac14610290578063b12957f61461028b578063b2185bb114610286578063bbc492c014610281578063bcfdf2191461027c578063bfbf228414610277578063c66944ba14610272578063ca232b091461026d578063cb5305f314610268578063d0a2c33614610263578063d547741f1461025e578063ea8a1af014610259578063f4c8770e14610254578063f7cb789a1461024f5763fa2f0a8d1461024a575f80fd5b6137ac565b613767565b6136f7565b613641565b6135e4565b61348d565b613346565b612b89565b612af1565b612a5f565b612a16565b6129a3565b6128e3565b61286a565b612821565b6127a0565b612768565b612723565b6126e1565b612664565b6125c0565b612473565b611f99565b611ddd565b611cb7565b611c0e565b611b58565b611aa2565b6119fa565b6119a9565b611941565b611901565b6118bf565b61173b565b611631565b6115e0565b61155f565b611483565b61132e565b611246565b611119565b611083565b610f1c565b610d1b565b610ca0565b610a21565b61096a565b610684565b6104a3565b610440565b610377565b7fffffffff0000000000000000000000000000000000000000000000000000000081160361037357565b5f80fd5b346103735760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103735760207fffffffff000000000000000000000000000000000000000000000000000000006004356103d581610349565b167f7965db0b00000000000000000000000000000000000000000000000000000000811490811561040c575b506040519015158152f35b7f01ffc9a7000000000000000000000000000000000000000000000000000000009150145f610401565b5f91031261037357565b34610373575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037357602064ffffffffff60035460d01c16604051908152f35b73ffffffffffffffffffffffffffffffffffffffff81160361037357565b346103735760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610373576004356104de81610485565b6104e6613ebb565b73ffffffffffffffffffffffffffffffffffffffff811690811561056e577fc1b5345cce283376356748dc57f2dfa7120431d016fc7ca9ba641bc65f91411d916020916bffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000006004549260601b16911617600455604051908152a1005b63aa7feadc5f526004601cfd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b67ffffffffffffffff81116105bc57604052565b61057b565b60e0810190811067ffffffffffffffff8211176105bc57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176105bc57604052565b67ffffffffffffffff81116105bc5760051b60200190565b92916106418261061e565b9161064f60405193846105dd565b829481845260208094019160051b810192831161037357905b8282106106755750505050565b81358152908301908301610668565b346103735760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103735760043560243567ffffffffffffffff81116103735736602382011215610373576106e7903690602481600401359101610636565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000095c68c52bb12a43069973fdcd88e4e93d2142f1016803303610933575061074261073b835f52600b60205260405f2090565b5460ff1690565b61074857005b61077861076e610760845f52600b60205260405f2090565b5460081c64ffffffffff1690565b64ffffffffff1690565b9061078b825f52600860205260405f2090565b906002610799835460ff1690565b6107a281612324565b146107aa575b005b6107bd906107b88484614d4b565b613b78565b51928360016107d581935f52600b60205260405f2090565b01556003808301918254906107e982613aa0565b925f5b8381106108ff575050506108e06107a8966108db6108ca61087a600361085e6002996108586108f79a60016108516108497fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6108ef9e0184613b85565b51809b613b1c565b01906154ca565b9061390e565b50015473ffffffffffffffffffffffffffffffffffffffff1690565b6108c360018a0191829073ffffffffffffffffffffffffffffffffffffffff167fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055565b5460a01c90565b6bffffffffffffffffffffffff1690565b613e74565b845460301c61ffff1690613e74565b612710900490565b910155614e67565b8061092261076e8461091287958b61390e565b50015460a81c64ffffffffff1690565b61092c8288613b85565b52016107ec565b604490604051907f1cf993f40000000000000000000000000000000000000000000000000000000082523360048301526024820152fd5b34610373575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610373576109a0613ebb565b7f67aa0e8084cf2c79566eed90861fb37a9bf4106afb0fd2ee5b3428b4a5767c7b60206003548060f81c15907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fff000000000000000000000000000000000000000000000000000000000000008360f81b16911617600355604051908152a1005b346103735760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037357600435610a5c81610485565b60243590610a6982610485565b610a71613ebb565b6040517fe12f3a61000000000000000000000000000000000000000000000000000000008082523060048301526020939092909173ffffffffffffffffffffffffffffffffffffffff91907f000000000000000000000000430000000000000000000000000000000000000483168682602481845afa908115610bd85787925f92610c81575b5081610bfa575b505060405194855250503060048401527f000000000000000000000000430000000000000000000000000000000000000316918381602481865afa908115610bd8575f91610bdd575b5080610b4f57005b6040517faad3ec9600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9290921660048301526024820152908290829060449082905f905af18015610bd857610bb257005b816107a892903d10610bd1575b610bc981836105dd565b8101906137ec565b503d610bbf565b6137fb565b610bf49150843d8611610bd157610bc981836105dd565b5f610b47565b6040517faad3ec9600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9490941660048501526024840191909152829060449082905f905af18015610bd857610c64575b848180610afe565b610c7a90853d8711610bd157610bc981836105dd565b505f610c5c565b610c99919250833d8511610bd157610bc981836105dd565b905f610af7565b346103735760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610373576004355f525f6020526020600160405f200154604051908152f35b9181601f840112156103735782359167ffffffffffffffff8311610373576020808501948460051b01011161037357565b34610373576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103735760043567ffffffffffffffff811161037357610d6b903690600401610cea565b90600192600260015414610ef2576002600155610d86613f00565b610d8e613806565b5f91610d9985613f1a565b5f5b858110610e595750507f573056d40bdb0e131a339ac518c08135633a29c4a83b7efb171c4f931fbf40d59450602081015180610e2a575b505080610df7575b50610deb6040519283923384613a73565b0390a16107a860018055565b610e24905a90337f00000000000000000000000043000000000000000000000000000000000000046142d1565b5f610dda565b610e4b610e52925173ffffffffffffffffffffffffffffffffffffffff1690565b33906141d8565b5f80610dd2565b80610e668892888861385c565b610e8f610e7c82355f52600860205260405f2090565b91610e8683613f2e565b858101906138a1565b610e9881613f1a565b60035f93015b818410610eaf575050505001610d9b565b90919297610ee8869189610ed9610ec78d888a6138fe565b35610ed3875482613f93565b8661390e565b50610ee381613fa8565b613fd7565b9801929190610e9e565b60046040517f1bbee726000000000000000000000000000000000000000000000000000000008152fd5b346103735760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037357602435600435610f5a82610485565b805f525f602052610f71600160405f2001546143f4565b805f525f60205260ff610fa58360405f209073ffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b541615610fae57005b805f525f602052610fe08260405f209073ffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b60017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082541617905573ffffffffffffffffffffffffffffffffffffffff339216907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d5f80a4005b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60209101126103735760043561ffff811681036103735790565b346103735761109136611048565b611099613ebb565b61ffff8116906109c4821161056e577fede4aee4284b8033b84c1aadcc51b229a4e46e6b42ab40092e237f07508b4626916020917fffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffff72ffff00000000000000000000000000000000006003549260881b16911617600355604051908152a1005b34610373575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103735761114f613ebb565b60025460ff8116156111e9575060025460ff8116156111bf577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166002557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6020604051338152a16107a861456d565b60046040517f6cd60201000000000000000000000000000000000000000000000000000000008152fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0060019161121561474d565b16176002557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a1005b346103735760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103735760243561128181610485565b3373ffffffffffffffffffffffffffffffffffffffff8216036112aa576107a890600435614603565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c6600000000000000000000000000000000006064820152fd5b34610373576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610373576004359061136a613ebb565b81156114385764ffffffffff60035460a81c16905f5b8381106113f4576107a87fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85857f0c4874e1a947afdb9c813baf258eec6a442b25531183f82046efc9760f640773604051806113ea85858360209093929193604081019481520152565b0390a10101614e67565b8060019184015f526008835261143260405f2060047fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b01611380565b63cbc4e0605f526004601cfd5b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60209101126103735760043564ffffffffff811681036103735790565b346103735761149136611445565b611499613ebb565b64ffffffffff811690610e10821161056e577fbdeccc4cf4c928bfff2005eee2fd4b91bb3d22035af62a93e35b1eedf853e3a3916020917fffffffffffffffffffffffffffffff0000000000ffffffffffffffffffffffff70ffffffffff0000000000000000000000006003549260601b16911617600355604051908152a1005b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6020910112610373576004356bffffffffffffffffffffffff811681036103735790565b34610373576bffffffffffffffffffffffff61157a3661151a565b611582613ebb565b16801561056e576020817f988fd919afedb9b211cf201222b0091d485871857d14d2a87946e1ee390a17f4927fffffffffffffffffffffffffffffffffffffffff0000000000000000000000006003541617600355604051908152a1005b34610373575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037357602073ffffffffffffffffffffffffffffffffffffffff60065416604051908152f35b346103735760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103735760043561166c81610485565b611674613ebb565b6002549073ffffffffffffffffffffffffffffffffffffffff8260081c166116dc5774ffffffffffffffffffffffffffffffffffffffff007fffffffffffffffffffffff0000000000000000000000000000000000000000ff9160081b169116176002555f80f35b63d6336f0d5f526004601cfd5b9060407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc83011261037357600435916024359067ffffffffffffffff82116103735761173791600401610cea565b9091565b611744366116e9565b600192919290600260015414610ef257600260015561176161474d565b80156118ba57611779835f52600860205260405f2090565b9361178385614783565b61178c856147cb565b5f61179683613aa0565b935f5b848110611823575050340361181e576117db7fa315167fc4200676e8597c5df065fafa8cecfeac15a8e2aded299a649e4a517593604051938493873386613b99565b0390a1611800825464ffffffffff90600385015491808260081c169160901c16614b39565b61180e575b6107a860018055565b61181791614b62565b5f80611805565b61056e565b80870190611839825f52600860205260405f2090565b9161184a6108ca8585015460a01c90565b9081156118a9575b61185c848261490e565b6118678389896138fe565b35906118738383613b1c565b61181e57816118979382889761188c84611891966149f7565b614ab5565b95613b6b565b936118a28289613b85565b5201611799565b90506118b48161482e565b90611852565b6146d8565b34610373575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037357602061ffff60035460981c16604051908152f35b34610373575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037357602060ff600254166040519015158152f35b346103735760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610373576004355f52600b602052606060405f206001815491015464ffffffffff6040519260ff81161515845260081c1660208301526040820152f35b34610373575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037357602073ffffffffffffffffffffffffffffffffffffffff60055416604051908152f35b34610373575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037357600260015414610ef2576002600155611a3f613f00565b64ffffffffff8060035460a81c16805f52600860205260405f2091611a6383613f51565b611a7281845460681c16613c0c565b164210611a9557611a8681611a8b93614da8565b614e67565b506107a860018055565b63f4c0ca6e5f526004601cfd5b346103735760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103735773ffffffffffffffffffffffffffffffffffffffff600435611af281610485565b611afa613ebb565b16801561056e576020817f2d5eba1cf3f9252b2aa813087328fc416c6c2ad0fb1417f9f5f78f08cb24cfdb927fffffffffffffffffffffffff00000000000000000000000000000000000000006005541617600555604051908152a1005b346103735760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103735773ffffffffffffffffffffffffffffffffffffffff600435611ba881610485565b611bb0613ebb565b16801561056e576020817fa75f06c1fcb711f11e4fe2a1e8b84e798cce8ea1c6d6db252abe31ebd836e21f927fffffffffffffffffffffffff00000000000000000000000000000000000000006006541617600655604051908152a1005b34610373575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037357602064ffffffffff60065460a01c16604051908152f35b8015150361037357565b60407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc820112610373576004359067ffffffffffffffff821161037357611ca691600401610cea565b9091602435611cb481611c53565b90565b3461037357611cc536611c5d565b5f92915f925f915b808310611d1b575050505f14611cfe5750611cea611cfa91614f8a565b6040519081529081906020820190565b0390f35b80821015611d11575050611cfa5f611cea565b611cfa9103611cea565b909194611d2986838561385c565b611d53611d3f82355f52600860205260405f2090565b91611d4983613f67565b60208101906138a1565b60038301908154915f5b828110611d835750505050506001916002611d7a92015490613b6b565b95019190611ccd565b611d8e8184876138fe565b3584811015611dd857611da1908361390e565b50805460ff16611db081612340565b15611dbf575b50600101611d5d565b6001919b6002611dd192015490613b6b565b9a90611db6565b613f9b565b611de636611c5d565b91600292600193600260015414610ef2576002600155611e04613f00565b611e0c613806565b915f955f9282611e1b88613f1a565b611f8e575b5f5b878110611efb5750505081611e79575b5050928360207ffbb3d671e318a7ebc6333ba95648c22dc746b01f141b5e81939d55d4664be29595015180610e2a57505080610df75750610deb6040519283923384613a73565b15611eb25790611eaa7ffbb3d671e318a7ebc6333ba95648c22dc746b01f141b5e81939d55d4664be2959592615079565b90935f611e32565b80611ebf611ec692615015565b3490613c51565b848111611ef6577ffbb3d671e318a7ebc6333ba95648c22dc746b01f141b5e81939d55d4664be295940390611eaa565b6146e5565b611f0681898961385c565b611f2f611f1c82355f52600860205260405f2090565b91611f2683613f67565b611d4983614fe6565b90611f3982613f1a565b5f91600384015b818410611f655750505050905f611f5d8486940197885490613b6b565b965501611e22565b9091929c611f8488918f611f7e610ec78f92888a6138fe565b50613fd7565b9d01929190611f40565b3415611e205761056e565b346103735760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037357600480359060243567ffffffffffffffff811161037357611fed903690600401610cea565b9160443590611ffb82611c53565b6002916001600260015414610ef257600260015561201761474d565b5f935f9361202488613f1a565b5f5b888110612182575050505081612152575b505061204b845f52600860205260405f2090565b61205481614783565b61205e818661490e565b612067816147cb565b6120786108ca600183015460a01c90565b946120838684613b1c565b80612113575b5085831061181e576120cb837fecd5c5544dcd4a5344389c360ff979c215f25290177e786ca2c407e58a95b88a976120c4610deb96856149f7565b8385614ab5565b91816120ef825464ffffffffff90600385015491808260081c169160901c16614b39565b612103575b50506040519485943386613c5e565b61210c91614b62565b5f816120f4565b928361214c91612121613f00565b03935a90337f00000000000000000000000043000000000000000000000000000000000000046142d1565b5f612089565b156121675761216090615079565b5f80612037565b908181105f036146e5578161217d910391615015565b612160565b61218d818a8a61385c565b6121a081355f52600860205260405f2090565b906121ac825460ff1690565b916121b683612324565b6003918284106122f2576121e2906121cd85612324565b8385146122d2575b60208195939501906138a1565b90926121ed82613f1a565b805f950192878114935b83871061220c57505050505050508301612026565b9091929394959c6122336122218f878a6138fe565b3561222d845482613f93565b8361390e565b5061223d816151a3565b805460ff1661224b81612340565b6122cd578b918b6122b2928961226088612324565b6122bf575b6122aa888201740100000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff825416179055565b015490613b6b565b9d019594939291906121f7565b6122c881613fa8565b612265565b6146f2565b6122db83614fe6565b5f6122eb8985019c8d5490613b6b565b9b556121d5565b613f44565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b6005111561232e57565b6122f7565b90600582101561232e5752565b6003111561232e57565b9698939590979492919260206101606101409961236a818c81019d612333565b829a64ffffffffff8098168483015261ffff6040971660408301528760609b166060830152876080951660808301528760a0961660a083015260c09873ffffffffffffffffffffffffffffffffffffffff9e8f1660c08401526bffffffffffffffffffffffff60e09b1660e08401526101008301526101208201528d51809c52019b01995f975b8a89106124075750505050505050505050505090565b909192939495969798999a9b8a896001928f8b8b9151805161242881612340565b8452808601518916868501528b8101518c85015287810151888501528981015189168a8501528a81015115158b8501520151168b820152019d019b9a990197969594939291906123f1565b346103735760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610373576004355f8181526008602052604090208054603081901c61ffff16929091611cfa91906124d7905460401c64ffffffffff1690565b906124fb6124ed825f52600860205260405f2090565b5460681c64ffffffffff1690565b61251e612510835f52600860205260405f2090565b5460901c64ffffffffff1690565b6125506001612535855f52600860205260405f2090565b015473ffffffffffffffffffffffffffffffffffffffff1690565b906125706001612568865f52600860205260405f2090565b015460a01c90565b926125a4600361259e600261258d895f52600860205260405f2090565b0154975f52600860205260405f2090565b01613c9d565b95604051998960ff64ffffffffff8d9c60081c1691168b61234a565b34610373576125ce36611445565b6125d6613ebb565b64ffffffffff8116906002821061056e577f32e1033127c5a25fa4a87832fb767338db2bca3d4eba8f34be6d5a8f71e92275916020917fff0000000000ffffffffffffffffffffffffffffffffffffffffffffffffffff7effffffffff00000000000000000000000000000000000000000000000000006003549260d01b16911617600355604051908152a1005b346103735760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037357602060ff6126d56024356126a681610485565b6004355f525f845260405f209073ffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b54166040519015158152f35b34610373575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037357602061ffff60035460881c16604051908152f35b34610373575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037357602064ffffffffff60035460a81c16604051908152f35b34610373575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103735760206040515f8152f35b34610373576bffffffffffffffffffffffff6127bb3661151a565b6127c3613ebb565b16801561056e576020817fab9b0becdb6bda45e0cb0aedf05c920174daf5b035652783df65736347ec8b98927fffffffffffffffffffffffffffffffffffffffff0000000000000000000000006004541617600455604051908152a1005b34610373575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103735760206bffffffffffffffffffffffff60035416604051908152f35b346103735760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103735760206128da6024356128aa81610485565b6004355f526009835260405f209073ffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b54604051908152f35b34610373575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037357600260015414610ef257600260015561292861474d565b64ffffffffff8060035460a81c16805f52600860205260405f209161294c83613f7d565b825490808260901c169161297161296d6003870154848460081c1686614b39565b1590565b612980575b6118058486614b62565b60401c16421061299e57600211612999575f8080612976565b6146ff565b6136e0565b346103735760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103735773ffffffffffffffffffffffffffffffffffffffff6004356129f381610485565b165f52600c60205260405f206024355f52602052602060405f2054604051908152f35b34610373575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103735760206bffffffffffffffffffffffff60045416604051908152f35b34610373577ff020ff23e722cd62b0e67a05c051cc3dc4b4d0c48e01de57a0571ad6a180c35d6020612a9036611445565b612a98613ebb565b6006547fffffffffffffff0000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000008360a01b1691161760065564ffffffffff60405191168152a1005b3461037357612aff36611048565b612b07613ebb565b61ffff811690612710821161056e577f2e38c85b973ddf3d7c0cbd813bddb9b63db96d86ff7b6ccce361777d674d813c916020917fffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffff74ffff000000000000000000000000000000000000006003549260981b16911617600355604051908152a1005b612b92366116e9565b91600260015414610ef2576002600155612baa61474d565b612bbc815f52600860205260405f2090565b612bc581614783565b612bcf818361490e565b612bd8816147cb565b6003810154935f905f94612bfc612bf7865f52600860205260405f2090565b613b58565b92346132b45782156118ba575b82612cb7575b505050612c81857f73a19dd210f1a7f902193214c0ee91dd35ee5b4d920cba8d519eca65a7b488ca968593612c5d612c57612c516108ca60018a015460a01c90565b8a613e74565b866149f7565b55835464ffffffffff808260901c1691612c7783856156b4565b60081c1690614b39565b612ca7575b50506040805133815260208101929092528101919091528060608101610deb565b612cb091614b62565b5f81612c86565b9190612cc2826151c0565b925f905b838210612dab575050505073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000007fe8d7666bb0da2a5d13f72b8dabab16803b1561037357612d505f929183926040519485809481937f0ca8e8a800000000000000000000000000000000000000000000000000000000835230903390600485016152d4565b03925af1958615610bd857808593612c81937f73a19dd210f1a7f902193214c0ee91dd35ee5b4d920cba8d519eca65a7b488ca99612d92575b50935096612c0f565b80612d9f612da5926105a8565b80610436565b5f612d89565b93979298612dbe828b859a949995615257565b94612dcb60208701613db7565b946001612e2d612dda89615297565b604051612e1c81612df060208201948d86613dc1565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018352826105dd565b5190205f52600760205260405f2090565b54036132af57612e6c84612e5f8873ffffffffffffffffffffffffffffffffffffffff165f52600c60205260405f2090565b905f5260205260405f2090565b546002612e7889615297565b612e8181612340565b0361306057801561301e575b612eae90612ea86108ca6001899e959798969e015460a01c90565b90613eb1565b93612eb885615756565b612ecf612ec860408a018a6138a1565b9050613aa0565b9a5f945b612ee060408b018b6138a1565b9050861015612f8a578c83808d898b98968f9a988e612f008c859a613b6b565b9b612f0a9361576a565b9960408101612f18916138a1565b612f2292916138fe565b3591612f36915f5260205f209060021b0190565b3379ffffffffff00000000000000000000000000000000000000000060a88b901b16176003820155600260088e901b1781556001015560010196612f7991613b85565b600190526001019491939092612ed3565b9c98613003929e965060019550612fca612feb92989c959d9499612fae878d613b85565b519073ffffffffffffffffffffffffffffffffffffffff169052565b612fe16020612fd9878d613b85565b510160019052565b60408101906138a1565b91906040612ff9868c613b85565b5101923691610636565b905260606130118389613b85565b5101525b01909291612cc6565b50612eae61302b88615808565b8061305887612e5f8b73ffffffffffffffffffffffffffffffffffffffff165f52600c60205260405f2090565b559050612e8d565b60016130768994979b959e969c98939d99615297565b61307f81612340565b14613090575b505050600190613015565b919a829c939c95919515613270575b6130b66130af60408e018e6138a1565b3691610636565b600181510361326b576130cb6130d391613b78565b518094613e74565b6040517f313ce56700000000000000000000000000000000000000000000000000000000815260208160048173ffffffffffffffffffffffffffffffffffffffff8c165afa8015610bd8576108ca60016131418f9495612ea8612ea89561314a985f9161323c575b50613ea0565b93015460a01c90565b9b6131548d615756565b6060918d8383013511613237578d8f8b88958f958c6131738585613b85565b5173ffffffffffffffffffffffffffffffffffffffff90911690526131988484613b85565b516020015f9052604081016131ac916138a1565b936131b79193613b85565b51019136906131c592610636565b90526131d091613b6b565b9c6131da9361576a565b936131ee83895f5260205f209060021b0190565b3379ffffffffff00000000000000000000000000000000000000000060a888901b1617600382015591600283015561322b919060081b6001179055565b600101985f8080613085565b61470c565b61325e915060203d602011613264575b61325681836105dd565b810190613e87565b5f61313b565b503d61324c565b613f21565b915061327b85615446565b91826132a98c612e5f8973ffffffffffffffffffffffffffffffffffffffff165f52600c60205260405f2090565b5561309f565b615439565b5094506132c86108ca600185015460a01c90565b6132d28134613b1c565b61181e576132e09034613eb1565b9460016132ee8789876156ea565b9761333561330582875f5260205f209060021b0190565b3379ffffffffff00000000000000000000000000000000000000000060a88d901b16176003820155349060020155565b0196612c09565b6003111561037357565b346103735760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103735760043567ffffffffffffffff811161037357613395903690600401610cea565b602435916133a28361333c565b604435926133af84611c53565b6133b76153f4565b6133c081612340565b80156132af575f5b83811061340757507f14f4f9b9a2d50cb168899c4825e24b7ffdc472b1dca88ddad74a834f7b62470b936134029160405194859485613e02565b0390a1005b600190851561348757815b6134806134286134238489896138fe565b613db7565b60ff6040519361346d856134418a602083019687613dc1565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018752866105dd565b16925190205f52600760205260405f2090565b55016133c8565b5f613412565b34610373577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60408136011261037357600435906024359067ffffffffffffffff82116103735760a09082360301126103735773ffffffffffffffffffffffffffffffffffffffff91602061355e61350760248501613db7565b9361353484612e5f8773ffffffffffffffffffffffffffffffffffffffff165f52600c60205260405f2090565b549081156135ca575b6135518160446135579301906004016138a1565b906138f5565b3590613e74565b926004604051809681937f313ce567000000000000000000000000000000000000000000000000000000008352165afa928315610bd8576108ca60016125686135bb611cea96612ea8611cfa99612ea8975f9161323c5750613ea0565b945f52600860205260405f2090565b90506135576135516135db87615446565b9291505061353d565b346103735760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610373576107a860243560043561362582610485565b805f525f60205261363c600160405f2001546143f4565b614603565b34610373575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037357600260015414610ef2576002600155613686613f00565b64ffffffffff8060035460a81c16805f52600860205260405f20916136aa83613f7d565b825490808260401c1680159081156136ed575b506136e05760019160901c16116136db57611a8681611a8b93614da8565b614719565b63f9ad93f55f526004601cfd5b905042105f6136bd565b346103735760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103735760206128da60243561373781610485565b6004355f52600a835260405f209073ffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b34610373575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037357602064ffffffffff60035460601c16604051908152f35b34610373575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037357602060035460f81c6040519015158152f35b90816020910312610373575190565b6040513d5f823e3d90fd5b604051906040820182811067ffffffffffffffff8211176105bc576040525f6020838281520152565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b919081101561389c5760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc181360301821215610373570190565b61382f565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610373570180359067ffffffffffffffff821161037357602001918160051b3603831361037357565b901561389c5790565b919081101561389c5760051b0190565b805482101561389c575f5260205f209060021b01905f90565b90918281527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83116103735760209260051b809284830137010190565b908290808452602080940193600592818360051b82010195855f925b85841061399257505050505050505090565b90919293949596977fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082820301845288357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc18436030181121561037357830160409080358352878101357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18236030181121561037357019087823592019267ffffffffffffffff831161037357828b1b360384136103735760019389938383869586613a619601520191613927565b9a019401940192969594939190613980565b60409073ffffffffffffffffffffffffffffffffffffffff611cb495931681528160208201520191613964565b90613aaa8261061e565b613ab760405191826105dd565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0613ae5829461061e565b0190602036910137565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b8115613b26570690565b613aef565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b9060038201809211613b6657565b613b2b565b91908201809211613b6657565b80511561389c5760200190565b805182101561389c5760209160051b010190565b92909373ffffffffffffffffffffffffffffffffffffffff613bd293951684526020946020850152608060408501526080840191613927565b906060818303910152602080845192838152019301915f5b828110613bf8575050505090565b835185529381019392810192600101613bea565b9062015f9064ffffffffff80931601918211613b6657565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8201918211613b6657565b91908203918211613b6657565b9160609373ffffffffffffffffffffffffffffffffffffffff613c939398979698168452608060208501526080840191613964565b9460408201520152565b908154613ca98161061e565b92604093613cba60405191826105dd565b82815280946020809201925f5260205f20905f935b858510613cde57505050505050565b6004846001928451613cef816105c1565b613da964ffffffffff8854613d9560ff808316613d0b81612340565b8652613d4973ffffffffffffffffffffffffffffffffffffffff809460081c168988019073ffffffffffffffffffffffffffffffffffffffff169052565b898c01548b87015260028c01546060870152613d8560038d0154938416608088019073ffffffffffffffffffffffffffffffffffffffff169052565b60a083811c909116151590860152565b60a81c1660c083019064ffffffffff169052565b815201930194019391613ccf565b35611cb481610485565b90917fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060159360601b168252613df681612340565b60f81b60148201520190565b92949391806060850160608652526080840191905f5b818110613e3c575050509060409194613e3081612340565b60208401521515910152565b90919260019073ffffffffffffffffffffffffffffffffffffffff8535613e6281610485565b16815260209081019401929101613e18565b81810292918115918404141715613b6657565b90816020910312610373575160ff811681036103735790565b60ff16604d8111613b6657600a0a90565b8115613b26570490565b335f9081527fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5602052604090205460ff1615613ef357565b6330cd74715f526004601cfd5b60035460f81c15613f0d57565b63010a265a5f526004601cfd5b15613f2157565b63947d5a845f526004601cfd5b5460ff16600581101561232e57600403613f4457565b63f525e3205f526004601cfd5b5460ff16600581101561232e57600203613f4457565b5460ff16600581101561232e57600303613f4457565b5460ff16600581101561232e57600103613f4457565b1015613f9b57565b6363df81715f526004601cfd5b6003015473ffffffffffffffffffffffffffffffffffffffff163303613fca57565b633cc50b455f526004601cfd5b90613fe1826151a3565b61402760038301740100000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff825416179055565b815460ff811661403681612340565b8061404b5750505060020154611cb491613b6b565b61405781949394612340565b600281036140915750508054611cb4925060019060081c73ffffffffffffffffffffffffffffffffffffffff169101549033903090615567565b8061409d600192612340565b146140a9575b50505090565b73ffffffffffffffffffffffffffffffffffffffff809160081c166140e2845173ffffffffffffffffffffffffffffffffffffffff1690565b918216810361410c575050602060026141019201549201918251613b6b565b90525b5f80806140a3565b61413f9084602060029594960195865180614148575b50509073ffffffffffffffffffffffffffffffffffffffff169052565b01549052614104565b6141539133906141d8565b5f80614122565b67ffffffffffffffff81116105bc57601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b3d156141be573d906141a58261415a565b916141b360405193846105dd565b82523d5f602084013e565b606090565b908160209103126103735751611cb481611c53565b919091803b156142a7576040517fa9059cbb000000000000000000000000000000000000000000000000000000006020820190815273ffffffffffffffffffffffffffffffffffffffff909416602482015260448101929092525f92839283906142458160648101612df0565b51925af1614251614194565b901561427d57805180614262575050565b8160208061296d9361427795010191016141c3565b61427d57565b60046040517ff1568f95000000000000000000000000000000000000000000000000000000008152fd5b60046040517f09ee12d5000000000000000000000000000000000000000000000000000000008152fd5b9091925f80808087876142e396f11590565b6142ec57505050565b73ffffffffffffffffffffffffffffffffffffffff1691823b1561037357604051927fd0e30db00000000000000000000000000000000000000000000000000000000084525f8460048185855af1928315610bd8576143a7946020946143e1575b505f6040518096819582947fa9059cbb000000000000000000000000000000000000000000000000000000008452600484016020909392919373ffffffffffffffffffffffffffffffffffffffff60408201951681520152565b03925af18015610bd8576143b9575b50565b6143b69060203d6020116143da575b6143d281836105dd565b8101906141c3565b503d6143c8565b80612d9f6143ee926105a8565b5f61434d565b805f525f60205260ff6144283360405f209073ffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b5416156144325750565b339061443c615a86565b91603061444884613b78565b53607861445484615ab3565b5360295b6001811161451f5761451b6144c06144e986612df06144808861447b8915615aff565b615b64565b6144ba6040519586946144ba602087016017907f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081520190565b90615649565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000815260110190565b6040519182917f08c379a0000000000000000000000000000000000000000000000000000000008352600483016156a3565b0390fd5b90600f811690601082101561389c577f3031323334353637383961626364656600000000000000000000000000000000614568921a61455e8487615ac3565b5360041c91615ad4565b614458565b64ffffffffff60035460a81c165f5b600181106145be57506143b6907f0c4874e1a947afdb9c813baf258eec6a442b25531183f82046efc9760f6407736040805183815260016020820152a1614e67565b8060019183015f5260086020526145fd60405f2060047fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b0161457c565b805f525f60205260ff6146378360405f209073ffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b5416614641575050565b805f525f6020526146738260405f209073ffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00815416905573ffffffffffffffffffffffffffffffffffffffff339216907ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b5f80a4565b63a95231d55f526004601cfd5b630134f2785f526004601cfd5b63a1e9dd9d5f526004601cfd5b637e439aed5f526004601cfd5b63f48cb8a05f526004601cfd5b637cd9dd6a5f526004601cfd5b63f90121325f526004601cfd5b63c11f59765f526004601cfd5b630da5618b5f526004601cfd5b60ff6002541661475957565b60046040517f1309a563000000000000000000000000000000000000000000000000000000008152fd5b5460ff8116600581101561232e57600114908115916147a4575b50613f4457565b60401c64ffffffffff168015159150816147c0575b505f61479d565b90504210155f6147b9565b805464ffffffffff808260401c16156147e357505050565b60035460601c164201804211613b66576cffffffffff00000000000000007fffffffffffffffffffffffffffffffffffffff0000000000ffffffffffffffff9160401b169116179055565b9060035460017fffffffffffffffffffffffff00000000000000000000000000000000000000006148766bffffffffffffffffffffffff8416955f52600860205260405f2090565b9267ffff0000000000008160581c1665ffffffffff008260c81c1617845560a01b16910155565b9060035460017fffffffffffffffffffffffff00000000000000000000000000000000000000006148e56bffffffffffffffffffffffff8416955f52600860205260405f2090565b928267ffff0000000000008260581c1665ffffffffff008360c81c161717845560a01b16910155565b805f52600960205261494060405f203373ffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b54908115614983575b600192505f526009602052016149803360405f209073ffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b55565b82549264ffffffffff93848160901c16948160081c1685146149ea577fffffffffffffffffff0000000000ffffffffffffffffffffffffffffffffffff16600194850160901b76ffffffffff00000000000000000000000000000000000016179055614949565b63b53a57db5f526004601cfd5b805f52600a602052614a2960405f203373ffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b54828101809111613b66576bffffffffffffffffffffffff6004541610614a8b575f52600a602052614a7c3360405f209073ffffffffffffffffffffffffffffffffffffffff165f5260205260405f2090565b8054918201809211613b665755565b60046040517f8369f344000000000000000000000000000000000000000000000000000000008152fd5b90919392938015613b26578404936003820154916001830193614b01614af2888664ffffffffff95614aed87825460901c168b6156b4565b6156ea565b915f52600860205260405f2090565b9360038501809511613b6657600292614b26614b3492875f5260205f209060021b0190565b921660a81b33176003830155565b015555565b9190821091821592614b4a57505090565b600110915081614b58575090565b6103e89150101590565b614bb190614b708382614e0a565b80547fffffffffffffffffffffffffffff0000000000ffffffffffffffffffffffffff164260681b71ffffffffff0000000000000000000000000016179055565b6040517f5d3b1d300000000000000000000000000000000000000000000000000000000081527f000000000000000000000000000000000000000000000000000000000000000060048201527f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1660248201527f000000000000000000000000000000000000000000000000000000000000000361ffff166044820152622625a060648201526001608482015260208160a4815f7f00000000000000000000000095c68c52bb12a43069973fdcd88e4e93d2142f1073ffffffffffffffffffffffffffffffffffffffff165af1908115610bd8575f91614d2c575b50614ccb61073b825f52600b60205260405f2090565b614d27577f3d94fecedaa4f90b8bd459797adb95f5bb11426025c5541390d9ccc1ad1b60a191815f52600b60205260405f208160081b6001179055614d226040519283928360209093929193604081019481520152565b0390a1565b614726565b614d45915060203d602011610bd157610bc981836105dd565b5f614cb5565b7ffbe046f0ca401af45e57af7a8efd3840294bfc077bf062f4b9919e2c028e161c9160409160037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055815190815260036020820152a1565b7ffbe046f0ca401af45e57af7a8efd3840294bfc077bf062f4b9919e2c028e161c91614dfb60409260047fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b815190815260046020820152a1565b7ffbe046f0ca401af45e57af7a8efd3840294bfc077bf062f4b9919e2c028e161c9160409160027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055815190815260026020820152a1565b600101906003547fffffffffffff0000000000ffffffffffffffffffffffffffffffffffffffffff79ffffffffff0000000000000000000000000000000000000000008460a81b1691161780600355614ec8835f52600860205260405f2090565b6bffffffffffffffffffffffff614ee3600183015460a01c90565b16614f2e575050614ef38261489d565b505b60408051838152600160208201527ffbe046f0ca401af45e57af7a8efd3840294bfc077bf062f4b9919e2c028e161c9181908101614d22565b54614f429060901c64ffffffffff1661076e565b90614f55845f52600860205260405f2090565b908154906001821793614f6b575b505055614ef5565b600192935064ffffffffff9060601c16420160401b1717905f80614f63565b670de0b6b3a76400009080820291820403613b6657614fb39061ffff60035460981c1690613e74565b614fd773ffffffffffffffffffffffffffffffffffffffff60025460081c16615446565b8015613b265761271091040490565b6001015473ffffffffffffffffffffffffffffffffffffffff16330361500857565b63618c72425f526004601cfd5b60407fa0c67dacab0c86ad0a872c2ed3fa9deb08f80f4f0543d481f2fac9ee41d026919161506b60045460601c825a917f00000000000000000000000043000000000000000000000000000000000000046142d1565b81519081525f6020820152a1565b61508290614f8a565b73ffffffffffffffffffffffffffffffffffffffff90817f00000000000000000000000000000000007fe8d7666bb0da2a5d13f72b8dabab169160025460081c1660045460601c833b156103735760845f928360405196879485937fda3e8ce4000000000000000000000000000000000000000000000000000000008552600485015233602485015260448401528660648401525af1918215610bd8577fa0c67dacab0c86ad0a872c2ed3fa9deb08f80f4f0543d481f2fac9ee41d0269192615190575b5060025460081c73ffffffffffffffffffffffffffffffffffffffff166040805192835273ffffffffffffffffffffffffffffffffffffffff909116602083015281908101614d22565b80612d9f61519d926105a8565b5f615146565b6003015460a01c60ff166151b357565b636507689f5f526004601cfd5b906151ca8261061e565b60406151d960405192836105dd565b8382527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0615207839561061e565b01905f5b8281106152185750505050565b815190608082019180831067ffffffffffffffff8411176105bc5760209284525f8152825f81830152606080868401528083015282870101520161520b565b919081101561389c5760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6181360301821215610373570190565b35611cb48161333c565b9081518082526020808093019301915f5b8281106152c0575050505090565b8351855293810193928101926001016152b2565b93919392909260609460608201606083528551809152608090608084019760808260051b860101986020809901935f925b848410615359575050505050509061533b604092615357959683019073ffffffffffffffffffffffffffffffffffffffff169052565b019073ffffffffffffffffffffffffffffffffffffffff169052565b565b90919293949a8a806153e4838f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff808d60019703018952519073ffffffffffffffffffffffffffffffffffffffff8251168152838201516153b881612340565b84820152866153d460408a81860151918501528a8401906152a1565b92015190878184039101526152a1565b9d01940194019294939190615305565b335f9081527fee57cd81e84075558e8fcc182a1f4393f91fc97f963a136e66b7f949a62f319f602052604090205460ff161561542c57565b637c214f045f526004601cfd5b63c1ab6dc15f526004601cfd5b602073ffffffffffffffffffffffffffffffffffffffff604481600554169360405194859384927fe3cae776000000000000000000000000000000000000000000000000000000008452166004830152610e1060248301525afa908115610bd8575f916154b1575090565b611cb4915060203d602011610bd157610bc981836105dd565b8051918215615560575f925b80841061553257508215159182615514575b505015611cb4577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b61552991925061552384613c24565b90613b85565b51145f806154e8565b61553c8185615a71565b90826155488386613b85565b51111561555557506154d6565b9350600101926154d6565b5050505f90565b909192813b156142a7576040519260208401947f23b872dd00000000000000000000000000000000000000000000000000000000865273ffffffffffffffffffffffffffffffffffffffff809216602486015216604484015260648301526064825260a082019282841067ffffffffffffffff8511176105bc575f809493819460405251925af16155f6614194565b50156155fe57565b60046040517fe0f5c508000000000000000000000000000000000000000000000000000000008152fd5b5f5b8381106156395750505f910152565b818101518382015260200161562a565b9061565c60209282815194859201615628565b0190565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f60209361569c81518092818752878088019101615628565b0116010190565b906020611cb4928181520190615660565b6103e8908181116156dd57146156c75750565b6001146156d057565b63ae24220e5f526004601cfd5b6327e6fcc75f526004601cfd5b91906156f582615756565b80615707575064ffffffffff91501690565b600392837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6157389301910161390e565b5064ffffffffff928391015460a81c16908101809111613b66571690565b1561575d57565b63f91214385f526004601cfd5b64ffffffffff9390841692831561578a575050821601908111613b665790565b90919250611cb493506156ea565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610373570180359067ffffffffffffffff82116103735760200191813603831361037357565b9190826040910312610373576020823561580281610485565b92013590565b9060808201357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81833603018112156103735782019160208091013561584c81610485565b6040840135934285118015615a49575b615a445760405191826158ca858201928360805f9193929373ffffffffffffffffffffffffffffffffffffffff60a08201957f60d14eec5d309c7bcbba8f8779f8070820b882731ce8afd4d9282a327dfe6ede835260016020840152610e1060408401521660608201520152565b03926158fc7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0948581018352826105dd565b5190209080358203615a3f57615a2a846159ec6159f8615a2f9673ffffffffffffffffffffffffffffffffffffffff9a615a37998701976159af61594a6159438b8b615798565b3691615c01565b878151910120926159a36040519384928a8401964692889094939260809260a08301967f8c01f2233cc36f533c3fbfd8037c653a0326c46e0dc25bff9aea020c1a72a05484526020840152604083015260608201520152565b038481018352826105dd565b5190209360405193849182019586603c917f19457468657265756d205369676e6564204d6573736167653a0a3332000000008252601c8201520190565b039081018352826105dd565b51902060065473ffffffffffffffffffffffffffffffffffffffff16615a246159436060860186615798565b91615c63565b615798565b8101906157e9565b92166132af57565b614740565b614733565b50615a6a615a6461076e60065464ffffffffff9060a01c1690565b86613b6b565b421161585c565b90808216911860011c8101809111613b665790565b604051906060820182811067ffffffffffffffff8211176105bc57604052602a8252604082602036910137565b80516001101561389c5760210190565b90815181101561389c570160200190565b8015613b66577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b15615b0657565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602060248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152fd5b604051906080820182811067ffffffffffffffff8211176105bc576040526042825260603660208401376030615b9983613b78565b536078615ba583615ab3565b536041905b60018211615bbd57611cb4915015615aff565b600f811690601082101561389c577f3031323334353637383961626364656600000000000000000000000000000000615bfb921a61455e8486615ac3565b90615baa565b929192615c0d8261415a565b91615c1b60405193846105dd565b829481845281830111610373578281602093845f960137010152565b908160209103126103735751611cb481610349565b604090611cb4939281528160208201520190615660565b91813b615cbd57615c749192615da4565b73ffffffffffffffffffffffffffffffffffffffff9081169116146153575760046040517fd1085d1b000000000000000000000000000000000000000000000000000000008152fd5b615d1073ffffffffffffffffffffffffffffffffffffffff926020926040519485809481937f1626ba7e00000000000000000000000000000000000000000000000000000000998a845260048401615c4c565b0392165afa8015610bd8577fffffffff00000000000000000000000000000000000000000000000000000000915f91615d75575b5016146153575760046040517ff6cd0e2f000000000000000000000000000000000000000000000000000000008152fd5b615d97915060203d602011615d9d575b615d8f81836105dd565b810190615c37565b5f615d44565b503d615d85565b815160418103615ee45750602082015191606060408201519101515f1a925b7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08211615eba5760ff8416601b8114159081615eae575b50615e7a576040805193845260ff949094166020808501919091529383015260608201525f8080529060809060015afa15610bd8575f519073ffffffffffffffffffffffffffffffffffffffff821615615e5057565b60046040517ff05a20c7000000000000000000000000000000000000000000000000000000008152fd5b6040517f417893a400000000000000000000000000000000000000000000000000000000815260ff85166004820152602490fd5b601c915014155f615dfa565b60046040517fc1851252000000000000000000000000000000000000000000000000000000008152fd5b60408103615f27575060406020830151920151601b7f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82169160ff1c0192615dc3565b6040517fd42b4bbd0000000000000000000000000000000000000000000000000000000081526004810191909152602490fdfea2646970667358221220c87ac4716d5663a44d1771fe149e28db2dbd3ac53e5cb91c2bc779d5375c852564736f6c63430008170033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000fb03340fdb69024c6579b35170f1b3c0d7d672420000000000000000000000002c64e6ee1dd9fc2a0db6a6b1aa2c3f163c7a2c7800000000000000000000000000000000000000000000000000000000000003e8000000000000000000000000000000000000000000000000000000000000007800000000000000000000000000000000000000000000000000038d7ea4c680000000000000000000000000006b86ff7863e27d1c8ccf05df9cb03b8efaa52125000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000013880000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000095c68c52bb12a43069973fdcd88e4e93d2142f10000000000000000000000000aeb1d03929bf87f69888f381e73fbf75753d75af00000000000000000000000000000000007fe8d7666bb0da2a5d13f72b8dabab0000000000000000000000009c9d8c8ee91f21004a40c4664d49cc1b9dfa69f90000000000000000000000004300000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000005a0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000430000000000000000000000000000000000000200000000000000000000000043000000000000000000000000000000000000030000000000000000000000002536fe9ab3f511540f2f9e2ec2a805005c3dd8000000000000000000000000004066b9bd584b5fa88897194dabe3a37883ac35f7
-----Decoded View---------------
Arg [0] : params (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
Arg [1] : _ethYieldConfiguration (address): 0x4300000000000000000000000000000000000002
Arg [2] : _usdbYieldConfiguration (address): 0x4300000000000000000000000000000000000003
Arg [3] : _blastPoints (address): 0x2536FE9ab3F511540F2f9e2eC2A805005C3Dd800
Arg [4] : _blastPointsOperator (address): 0x4066b9BD584b5FA88897194dAbE3a37883AC35F7
-----Encoded View---------------
21 Constructor Arguments found :
Arg [0] : 000000000000000000000000fb03340fdb69024c6579b35170f1b3c0d7d67242
Arg [1] : 0000000000000000000000002c64e6ee1dd9fc2a0db6a6b1aa2c3f163c7a2c78
Arg [2] : 00000000000000000000000000000000000000000000000000000000000003e8
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000078
Arg [4] : 00000000000000000000000000000000000000000000000000038d7ea4c68000
Arg [5] : 0000000000000000000000006b86ff7863e27d1c8ccf05df9cb03b8efaa52125
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000064
Arg [7] : 0000000000000000000000000000000000000000000000000000000000001388
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [10] : 00000000000000000000000095c68c52bb12a43069973fdcd88e4e93d2142f10
Arg [11] : 000000000000000000000000aeb1d03929bf87f69888f381e73fbf75753d75af
Arg [12] : 00000000000000000000000000000000007fe8d7666bb0da2a5d13f72b8dabab
Arg [13] : 0000000000000000000000009c9d8c8ee91f21004a40c4664d49cc1b9dfa69f9
Arg [14] : 0000000000000000000000004300000000000000000000000000000000000004
Arg [15] : 000000000000000000000000000000000000000000000000000000000000005a
Arg [16] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [17] : 0000000000000000000000004300000000000000000000000000000000000002
Arg [18] : 0000000000000000000000004300000000000000000000000000000000000003
Arg [19] : 0000000000000000000000002536fe9ab3f511540f2f9e2ec2a805005c3dd800
Arg [20] : 0000000000000000000000004066b9bd584b5fa88897194dabe3a37883ac35f7
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
[ Download: CSV Export ]
[ 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.