Source Code
Overview
ETH Balance
0.0326 ETH
More Info
ContractCreator
Multichain Info
N/A
Latest 25 from a total of 431 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Buy Entry | 7405116 | 48 days ago | IN | 0.005 ETH | 0.00290336 | ||||
Stake ETH | 7405105 | 48 days ago | IN | 0.001 ETH | 0.00373464 | ||||
Create Raffle | 7405103 | 48 days ago | IN | 0 ETH | 0.01238617 | ||||
Buy Entry | 7386711 | 50 days ago | IN | 0.005 ETH | 0.00048418 | ||||
Stake ETH | 7386708 | 50 days ago | IN | 0.001 ETH | 0.00053051 | ||||
Create Raffle | 7386706 | 50 days ago | IN | 0 ETH | 0.00294381 | ||||
Buy Entry | 7386275 | 50 days ago | IN | 0.001 ETH | 0.00056732 | ||||
Buy Entry | 7386263 | 50 days ago | IN | 0.001 ETH | 0.00049905 | ||||
Stake ETH | 7386260 | 50 days ago | IN | 0.001 ETH | 0.00055456 | ||||
Create Raffle | 7386258 | 50 days ago | IN | 0 ETH | 0.00148101 | ||||
Cancel Raffle | 6537976 | 182 days ago | IN | 0 ETH | 0.00009022 | ||||
Buy Entry | 6537973 | 182 days ago | IN | 0.001 ETH | 0.0001894 | ||||
Stake ETH | 6537966 | 182 days ago | IN | 0.001 ETH | 0.00020629 | ||||
Create Raffle | 6537961 | 182 days ago | IN | 0 ETH | 0.00083545 | ||||
Cancel Raffle | 6537926 | 182 days ago | IN | 0 ETH | 0.00008194 | ||||
Buy Entry | 6537922 | 182 days ago | IN | 0.001 ETH | 0.00017895 | ||||
Stake ETH | 6537918 | 182 days ago | IN | 0.001 ETH | 0.00019511 | ||||
Create Raffle | 6537902 | 182 days ago | IN | 0 ETH | 0.0007626 | ||||
Cancel Raffle | 6409735 | 203 days ago | IN | 0 ETH | 0.00036638 | ||||
Cancel Raffle | 6409717 | 203 days ago | IN | 0 ETH | 0.00038363 | ||||
Cancel Raffle | 6409699 | 203 days ago | IN | 0 ETH | 0.00044292 | ||||
Cancel Raffle | 6409698 | 203 days ago | IN | 0 ETH | 0.0004425 | ||||
Buy Entry | 6402859 | 204 days ago | IN | 0.0001 ETH | 0.00225519 | ||||
Cancel Raffle | 6379832 | 207 days ago | IN | 0 ETH | 0.00159796 | ||||
Give Batch Entri... | 6378376 | 208 days ago | IN | 0 ETH | 0.00325923 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
6537976 | 182 days ago | 0.001 ETH | ||||
6537926 | 182 days ago | 0.001 ETH | ||||
6409735 | 203 days ago | 0.1 ETH | ||||
6409717 | 203 days ago | 0.001 ETH | ||||
6379832 | 207 days ago | 0.001 ETH | ||||
5545702 | 332 days ago | 0.001 ETH | ||||
5477080 | 343 days ago | 0.001 ETH | ||||
5477080 | 343 days ago | 0.0001 ETH | ||||
5476998 | 343 days ago | 0.001 ETH | ||||
5476998 | 343 days ago | 0.0001 ETH | ||||
5476998 | 343 days ago | 0.001 ETH | ||||
5476998 | 343 days ago | 0.0001 ETH | ||||
5476920 | 343 days ago | 0.1 ETH | ||||
5476920 | 343 days ago | 0.0002 ETH | ||||
5476919 | 343 days ago | 0.001 ETH | ||||
5476919 | 343 days ago | 0.0001 ETH | ||||
5476919 | 343 days ago | 0.001 ETH | ||||
5476919 | 343 days ago | 0.0001 ETH | ||||
5466854 | 344 days ago | 0.001 ETH | ||||
5466854 | 344 days ago | 0.0008 ETH | ||||
5422834 | 350 days ago | 0.0001 ETH | ||||
5422834 | 350 days ago | 0.0001 ETH | ||||
5422658 | 350 days ago | 0.0001 ETH | ||||
5422658 | 350 days ago | 0.0001 ETH | ||||
5395118 | 354 days ago | 0.0001 ETH |
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
ETHComp
Compiler Version
v0.8.23+commit.f704f362
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.22; import "../lib/BaseCompetition.sol"; /// @title Raffles manager (lean, single winner and a fixed amount of ETH as prize) /// @author Luis Pando /// @notice It consumes VRF v1 from Chainlink. It has the role /// "operator" that is the one used by a backend app to make some calls /// @dev It saves in an ordered array the player wallet and the current /// entries count. So buying entries has a complexity of O(1) /// For calculating the winner, from the huge random number generated by Chainlink /// a normalized random is generated by using the module method, adding 1 to have /// a random from 1 to entriesCount. /// So next step is to perform a binary search on the ordered array to get the /// player O(log n) /// Example: /// 0 -> { 1, player1} as player1 buys 1 entry /// 1 -> {51, player2} as player2 buys 50 entries /// 2 -> {52, player3} as player3 buys 1 entry /// 3 -> {53, player4} as player4 buys 1 entry /// 4 -> {153, player5} as player5 buys 100 entries /// So the setWinner method performs a binary search on that sorted array to get the upper bound. /// If the random number generated is 150, the winner is player5. If the random number is 20, winner is player2 contract ETHComp is BaseCompetition { constructor( address _vrfCoordinator, bytes32 _keyHash, uint64 _subId, uint16 _minimumRequestConfirmations, uint32 _callbackGasLimit, uint32 _numWords) payable BaseCompetition(_vrfCoordinator, _keyHash, _subId, _minimumRequestConfirmations, _callbackGasLimit, _numWords) {} ////////////////////////////////////////////// /// @param _desiredFundsInWeis the amount the seller would like to get from the raffle /// @param _collateralAddress The address of the NFT of the raffle /// @param _collateralId The id of the NFT (ERC721) /// @param _minimumFundsInWeis The mininum amount required for the raffle to set a winner /// @param _prices Array of prices and amount of entries the customer could purchase // /// @param _commissionInBasicPoints commission for the platform, in basic points /// @notice Creates a raffle /// @dev creates a raffle struct and push it to the raffles array. Some data is stored in the funding data structure /// sends an event when finished /// @return raffleId function createRaffle( uint128 _desiredFundsInWeis, uint256 _prizeNumber, uint128 _minimumFundsInWeis, PriceStructure[] calldata _prices, uint48 _commissionInBasicPoints, ENTRY_TYPE _entryType ) external onlyRole(OPERATOR_ROLE) returns (uint256) { if (_commissionInBasicPoints > 5000) revert CreateRaffleError("commission too high"); createRaffleActions( _desiredFundsInWeis, address(0), _prizeNumber, _minimumFundsInWeis, _prices, _commissionInBasicPoints, _entryType ); saveEntryInfo(); uint256 idRaffle = raffles.length - 1; return idRaffle; } /// @param _raffleId Id of the raffle function stakeETH(uint256 _raffleId) external payable { EntryInfoStruct storage entryInfo = rafflesEntryInfo[_raffleId]; RaffleStruct storage raffle = raffles[_raffleId]; // Check if the raffle is already created require(entryInfo.status == STATUS.CREATED, "Raffle not CREATED"); // check the amount staked is the correct require(raffle.prizeNumber == msg.value, "Prize not staked"); entryInfo.status = STATUS.ACCEPTED; raffle.seller = msg.sender; emit RaffleStarted(_raffleId, msg.sender); } // The operator can call this method once they receive the event "RandomNumberCreated" // triggered by the VRF v1 consumer contract (RandomNumber.sol) /// @param _raffleId Id of the raffle /// @param _normalizedRandomNumber index of the array that contains the winner of the raffle. Generated by chainlink /// @notice it is the method that sets the winner and transfers funds and nft /// @dev called by Chainlink callback function transferPrizesAndFunds( uint256 _raffleId, uint256 _normalizedRandomNumber ) internal override { RaffleStruct memory raffle = transferPrizesAndFundsActions(_raffleId, _normalizedRandomNumber); transferETHTo(raffle.prizeNumber, raffle.winner); } /// @param _raffleId Id of the raffle /// @dev The operator can cancel the raffle. The NFT is sent back to the seller /// The raised funds are send to the destination wallet. The buyers will /// be refunded offchain in the metawin wallet function cancelRaffle(uint256 _raffleId) external override onlyRole(OPERATOR_ROLE) { _cancelRaffleActions(_raffleId, 1); } /// @dev callable by players. Depending on the number of entries assigned to the price structure the player buys (_id parameter) /// one or more entries will be assigned to the player. /// Also it is checked the maximum number of entries per user is not reached /// As the method is payable, in msg.value there will be the amount paid by the user /// @notice If the operator set requiredNFTs when creating the raffle, only the owners of nft on that collection can make a call to this method. This will be /// used for special raffles /// @param _raffleId: id of the raffle /// @param _id: id of the price structure function buyEntry(uint256 _raffleId, uint256 _id) virtual external payable { EntryInfoStruct memory entryInfo = buyEntryActions(_raffleId, _id); _checkWalletsCap(entryInfo, _raffleId, /*msg.sender,*/ _id); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol) pragma solidity ^0.8.20; import {IAccessControl} from "./IAccessControl.sol"; import {Context} from "../utils/Context.sol"; import {ERC165} from "../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 account => bool) hasRole; bytes32 adminRole; } mapping(bytes32 role => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Modifier that checks that an account has a specific role. Reverts * with an {AccessControlUnauthorizedAccount} error including the required role. */ 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 returns (bool) { return _roles[role].hasRole[account]; } /** * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()` * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier. */ function _checkRole(bytes32 role) internal view virtual { _checkRole(role, _msgSender()); } /** * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account` * is missing `role`. */ function _checkRole(bytes32 role, address account) internal view virtual { if (!hasRole(role, account)) { revert AccessControlUnauthorizedAccount(account, role); } } /** * @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 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 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 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 `callerConfirmation`. * * May emit a {RoleRevoked} event. */ function renounceRole(bytes32 role, address callerConfirmation) public virtual { if (callerConfirmation != _msgSender()) { revert AccessControlBadConfirmation(); } _revokeRole(role, callerConfirmation); } /** * @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 Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted. * * Internal function without access restriction. * * May emit a {RoleGranted} event. */ function _grantRole(bytes32 role, address account) internal virtual returns (bool) { if (!hasRole(role, account)) { _roles[role].hasRole[account] = true; emit RoleGranted(role, account, _msgSender()); return true; } else { return false; } } /** * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked. * * Internal function without access restriction. * * May emit a {RoleRevoked} event. */ function _revokeRole(bytes32 role, address account) internal virtual returns (bool) { if (hasRole(role, account)) { _roles[role].hasRole[account] = false; emit RoleRevoked(role, account, _msgSender()); return true; } else { return false; } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol) pragma solidity ^0.8.20; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControl { /** * @dev The `account` is missing a role. */ error AccessControlUnauthorizedAccount(address account, bytes32 neededRole); /** * @dev The caller of a function is not the expected one. * * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}. */ error AccessControlBadConfirmation(); /** * @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. */ 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 `callerConfirmation`. */ function renounceRole(bytes32 role, address callerConfirmation) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the value of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the value of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves a `value` amount of tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 value) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the * allowance mechanism. `value` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 value) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.20; import {IERC165} from "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon * a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or * {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon * a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must * understand this adds an external call which potentially creates a reentrancy vulnerability. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 tokenId) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the address zero. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Context.sol) pragma solidity ^0.8.20; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "./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); * } * ``` */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @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 v5.0.0) (utils/math/Math.sol) pragma solidity ^0.8.20; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Muldiv operation overflow. */ error MathOverflowedMulDiv(); enum Rounding { Floor, // Toward negative infinity Ceil, // Toward positive infinity Trunc, // Toward zero Expand // Away from zero } /** * @dev Returns the addition of two unsigned integers, with an overflow flag. */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the subtraction of two unsigned integers, with an overflow flag. */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a / b); } } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @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 towards infinity instead * of rounding towards zero. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { if (b == 0) { // Guarantee the same behavior as in a regular Solidity division. return a / b; } // (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 = x * y; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) 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. if (denominator <= prod1) { revert MathOverflowedMulDiv(); } /////////////////////////////////////////////// // 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. uint256 twos = denominator & (0 - denominator); 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 (unsignedRoundsUp(rounding) && 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 * towards zero. * * 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 + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2 of a positive value rounded towards zero. * 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 + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10 of a positive value rounded towards zero. * 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 + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256 of a positive value rounded towards zero. * 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 + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0); } } /** * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers. */ function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) { return uint8(rounding) % 2 == 1; } }
// SPDX-License-Identifier: CC0-1.0 pragma solidity ^0.8.17; /** * @title An immutable registry contract to be deployed as a standalone primitive * @dev See EIP-5639, new project launches can read previous cold wallet -> hot wallet delegations * from here and integrate those permissions into their flow */ interface IDelegationRegistry { /// @notice Delegation type enum DelegationType { NONE, ALL, CONTRACT, TOKEN } /// @notice Info about a single delegation, used for onchain enumeration struct DelegationInfo { DelegationType type_; address vault; address delegate; address contract_; uint256 tokenId; } /// @notice Info about a single contract-level delegation struct ContractDelegation { address contract_; address delegate; } /// @notice Info about a single token-level delegation struct TokenDelegation { address contract_; uint256 tokenId; address delegate; } /// @notice Emitted when a user delegates their entire wallet event DelegateForAll(address vault, address delegate, bool value); /// @notice Emitted when a user delegates a specific contract event DelegateForContract(address vault, address delegate, address contract_, bool value); /// @notice Emitted when a user delegates a specific token event DelegateForToken(address vault, address delegate, address contract_, uint256 tokenId, bool value); /// @notice Emitted when a user revokes all delegations event RevokeAllDelegates(address vault); /// @notice Emitted when a user revoes all delegations for a given delegate event RevokeDelegate(address vault, address delegate); /** * ----------- WRITE ----------- */ /** * @notice Allow the delegate to act on your behalf for all contracts * @param delegate The hotwallet to act on your behalf * @param value Whether to enable or disable delegation for this address, true for setting and false for revoking */ function delegateForAll(address delegate, bool value) external; /** * @notice Allow the delegate to act on your behalf for a specific contract * @param delegate The hotwallet to act on your behalf * @param contract_ The address for the contract you're delegating * @param value Whether to enable or disable delegation for this address, true for setting and false for revoking */ function delegateForContract(address delegate, address contract_, bool value) external; /** * @notice Allow the delegate to act on your behalf for a specific token * @param delegate The hotwallet to act on your behalf * @param contract_ The address for the contract you're delegating * @param tokenId The token id for the token you're delegating * @param value Whether to enable or disable delegation for this address, true for setting and false for revoking */ function delegateForToken(address delegate, address contract_, uint256 tokenId, bool value) external; /** * @notice Revoke all delegates */ function revokeAllDelegates() external; /** * @notice Revoke a specific delegate for all their permissions * @param delegate The hotwallet to revoke */ function revokeDelegate(address delegate) external; /** * @notice Remove yourself as a delegate for a specific vault * @param vault The vault which delegated to the msg.sender, and should be removed */ function revokeSelf(address vault) external; /** * ----------- READ ----------- */ /** * @notice Returns all active delegations a given delegate is able to claim on behalf of * @param delegate The delegate that you would like to retrieve delegations for * @return info Array of DelegationInfo structs */ function getDelegationsByDelegate(address delegate) external view returns (DelegationInfo[] memory); /** * @notice Returns an array of wallet-level delegates for a given vault * @param vault The cold wallet who issued the delegation * @return addresses Array of wallet-level delegates for a given vault */ function getDelegatesForAll(address vault) external view returns (address[] memory); /** * @notice Returns an array of contract-level delegates for a given vault and contract * @param vault The cold wallet who issued the delegation * @param contract_ The address for the contract you're delegating * @return addresses Array of contract-level delegates for a given vault and contract */ function getDelegatesForContract(address vault, address contract_) external view returns (address[] memory); /** * @notice Returns an array of contract-level delegates for a given vault's token * @param vault The cold wallet who issued the delegation * @param contract_ The address for the contract holding the token * @param tokenId The token id for the token you're delegating * @return addresses Array of contract-level delegates for a given vault's token */ function getDelegatesForToken(address vault, address contract_, uint256 tokenId) external view returns (address[] memory); /** * @notice Returns all contract-level delegations for a given vault * @param vault The cold wallet who issued the delegations * @return delegations Array of ContractDelegation structs */ function getContractLevelDelegations(address vault) external view returns (ContractDelegation[] memory delegations); /** * @notice Returns all token-level delegations for a given vault * @param vault The cold wallet who issued the delegations * @return delegations Array of TokenDelegation structs */ function getTokenLevelDelegations(address vault) external view returns (TokenDelegation[] memory delegations); /** * @notice Returns true if the address is delegated to act on the entire vault * @param delegate The hotwallet to act on your behalf * @param vault The cold wallet who issued the delegation */ function checkDelegateForAll(address delegate, address vault) external view returns (bool); /** * @notice Returns true if the address is delegated to act on your behalf for a token contract or an entire vault * @param delegate The hotwallet to act on your behalf * @param contract_ The address for the contract you're delegating * @param vault The cold wallet who issued the delegation */ function checkDelegateForContract(address delegate, address vault, address contract_) external view returns (bool); /** * @notice Returns true if the address is delegated to act on your behalf for a specific token, the token's contract or an entire vault * @param delegate The hotwallet to act on your behalf * @param contract_ The address for the contract you're delegating * @param tokenId The token id for the token you're delegating * @param vault The cold wallet who issued the delegation */ function checkDelegateForToken(address delegate, address vault, address contract_, uint256 tokenId) external view returns (bool); }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.22; import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "../lib/Constants.sol"; import "./MinimalBase.sol"; /// @title Raffles manager (lean, delegate.cash, single winner, nft gated with an nft from each whitelisted collection and a fixed amount of ETH as prize) /// @author Luis Pando /// @author Nathan Goodwin - revertCloseRequested function /// @notice It consumes VRF v1 from Chainlink. It has the role /// "operator" that is the one used by a backend app to make some calls /// @dev It saves in an ordered array the player wallet and the current /// entries count. So buying entries has a complexity of O(1) /// For calculating the winner, from the huge random number generated by Chainlink /// a normalized random is generated by using the module method, adding 1 to have /// a random from 1 to entriesCount. /// So next step is to perform a binary search on the ordered array to get the /// player O(log n) /// Example: /// 0 -> { 1, player1} as player1 buys 1 entry /// 1 -> {51, player2} as player2 buys 50 entries /// 2 -> {52, player3} as player3 buys 1 entry /// 3 -> {53, player4} as player4 buys 1 entry /// 4 -> {153, player5} as player5 buys 100 entries /// So the setWinner method performs a binary search on that sorted array to get the upper bound. /// If the random number generated is 150, the winner is player5. If the random number is 20, winner is player2 abstract contract BaseCompetition is Constants, MinimalBase { event RaffleStatusUpdated( uint256 indexed raffleId, STATUS newStatus ); constructor( address _vrfCoordinator, bytes32 _keyHash, uint64 _subId, uint16 _minimumRequestConfirmations, uint32 _callbackGasLimit, uint32 _numWords) payable MinimalBase(_vrfCoordinator, _keyHash, _subId, _minimumRequestConfirmations, _callbackGasLimit, _numWords) {} /** * @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 override { // randomness is the actual random number. Now extract from the aux map the original param id of the call RaffleInfo memory raffleInfo = chainlinkRaffleInfo[requestId]; // save the random number on the map with the original id as key uint256 normalizedRandomNumber = (randomWords[0] % raffleInfo.size) + 1; RandomResult memory result = RandomResult({ randomNumber: randomWords[0], nomalizedRandomNumber: normalizedRandomNumber }); requests[raffleInfo.id] = result; // send the event with the original id and the random number emit RandomNumberCreated( raffleInfo.id, randomWords[0], normalizedRandomNumber ); transferPrizesAndFunds(raffleInfo.id, normalizedRandomNumber); } function transferPrizesAndFunds( uint256 idRaffle, uint256 normalizedRandomNumber ) internal virtual; function saveEntryInfo() internal { EntryInfoStruct memory entryInfo = EntryInfoStruct({ status: STATUS.CREATED, amountRaised: 0, entriesLength: 0, walletsCap: 0, requireWhitelisting: false }); rafflesEntryInfo.push(entryInfo); } function saveEntryInfo( address[] calldata _whitelist, uint48 _walletsCap, uint256 _raffleId ) internal virtual {} function buyEntryActions( uint256 _raffleId, uint256 _id ) internal returns (EntryInfoStruct memory) { if (tx.origin != msg.sender) revert EntryNotAllowed("No contracts allowed"); EntryInfoStruct storage entryInfo = rafflesEntryInfo[_raffleId]; // 06.05.2023 To avoid late players to buy entries after the draw if (entryInfo.status != STATUS.ACCEPTED) revert EntryNotAllowed("Not in ACCEPTED"); // Price checks PriceStructure memory priceStruct = pricesList[_id]; if (priceStruct.id != _raffleId) revert EntryNotAllowed("Id not in raffleId"); uint48 numEntries = priceStruct.numEntries; if (msg.value != priceStruct.price) revert EntryNotAllowed("msg.value not the price"); if (priceStruct.price == 0) { bytes32 hash = keccak256(abi.encode(msg.sender, _raffleId)); if (freeEntriesPerWallet[hash] == true) revert EntryNotAllowed("Player already got free entry"); freeEntriesPerWallet[hash] = true; } // save the entries onchain uint48 entriesLength = entryInfo.entriesLength; EntriesBought memory entryBought = EntriesBought({ player: msg.sender, currentEntriesLength: uint48(entriesLength + numEntries) }); entriesList[_raffleId].push(entryBought); delete entriesList[_raffleId][0]; // update raffle variables entryInfo.amountRaised += uint128(msg.value); entryInfo.entriesLength = entriesLength + numEntries; emit EntrySold(_raffleId, msg.sender, entryInfo.entriesLength, _id); return entryInfo; } function buyEntriesRequiredNFTCheck( address col, uint256 id, uint256 _raffleId, address sender ) internal { bytes32 collectionHash = keccak256(abi.encode(col, _raffleId)); require( whitelistCollections[collectionHash] == true, "Not in required collection" ); IERC721 requiredNFT = IERC721(col); // 06.06.23 Richard asked for a contract to have 2 nfts or different collections in // order to let players participate require(requiredNFT.ownerOf(id) == sender, "Not the owner of tokenId"); bytes32 hashRequiredNFT = keccak256(abi.encode(col, _raffleId, id)); // check the tokenId has not been using yet in the raffle, to avoid abuse if (requiredNFTWallets[hashRequiredNFT] == address(0)) { requiredNFTWallets[hashRequiredNFT] = sender; } else require( requiredNFTWallets[hashRequiredNFT] == sender, "tokenId used" ); } function _checkWalletsCap( EntryInfoStruct memory entryInfo, uint256 _raffleId, uint256 _id ) internal { // 31.05.23 wallet cap if (entryInfo.walletsCap > 0) { PriceStructure memory priceStruct = pricesList[_id]; bytes32 entriesCountHash = keccak256( abi.encode(_raffleId, msg.sender) ); uint48 entriesCount = walletsCap[entriesCountHash]; if (entriesCount + priceStruct.numEntries > entryInfo.walletsCap) revert EntryNotAllowed("Wallet already used"); // update wallet cap of current user walletsCap[entriesCountHash] = walletsCap[entriesCountHash] + priceStruct.numEntries; } } // The operator can add free entries to the raffle /// @param _raffleId Id of the raffle /// @param _freePlayers array of addresses corresponding to the wallet of the users that won a free entrie /// @dev only operator can make this call. Assigns a single entry per user, except if that user already reached the max limit of entries per user function giveBatchEntriesForFree( uint256 _raffleId, address[] memory _freePlayers ) external onlyRole(OPERATOR_ROLE) { EntryInfoStruct storage entryInfo = rafflesEntryInfo[_raffleId]; require( entryInfo.status == STATUS.ACCEPTED, "Raffle is not in accepted" ); uint256 freePlayersLength = _freePlayers.length; uint48 validPlayersCount; for (uint256 i; i < freePlayersLength; ++i) { address entry = _freePlayers[i]; { // add a new element to the entriesBought array. // as this method only adds 1 entry per call, the amountbought is always 1 EntriesBought memory entryBought = EntriesBought({ player: entry, currentEntriesLength: uint48( entryInfo.entriesLength + i + 1 ) }); entriesList[_raffleId].push(entryBought); unchecked { ++validPlayersCount; } } } entryInfo.entriesLength = entryInfo.entriesLength + validPlayersCount; emit FreeEntry( _raffleId, _freePlayers, freePlayersLength, entryInfo.entriesLength ); } function _setWinnerActions( uint256 _raffleId ) internal virtual returns (EntryInfoStruct memory) { EntryInfoStruct storage entryInfo = rafflesEntryInfo[_raffleId]; // RaffleStruct storage raffle = raffles[_raffleId]; FundingStructure storage funding = fundingList[_raffleId]; // Check if the raffle is already accepted or is called again because early cashout failed require(entryInfo.status == STATUS.ACCEPTED, "Raffle in wrong status"); require( entryInfo.amountRaised >= funding.minimumFundsInWeis, "Not enough funds raised" ); require( funding.desiredFundsInWeis <= entryInfo.amountRaised, "Desired funds not raised" ); entryInfo.status = STATUS.CLOSING_REQUESTED; emit SetWinnerTriggered(_raffleId, entryInfo.amountRaised); return entryInfo; } /// @param _raffleId Id of the raffle /// @notice the operator finish the raffle, if the desired funds has been reached /// @dev it triggers Chainlink VRF1 consumer, and generates a random number that is normalized and checked that corresponds to a MW player function setWinner(uint256 _raffleId) external onlyRole(OPERATOR_ROLE) { EntryInfoStruct memory raffle = _setWinnerActions(_raffleId); // this call trigers the VRF v1 process from Chainlink uint256 requestId = _callVRFAndGetRequestId(); _getRandomNumber(_raffleId, raffle.entriesLength, requestId); } /// @param _newAddress new address of the platform /// @dev Change the wallet of the platform. The one that will receive the platform fee when the raffle is closed. /// Only the admin can change this function setDestinationAddress( address payable _newAddress ) external onlyRole(DEFAULT_ADMIN_ROLE) { destinationWallet = _newAddress; } /// @param _raffleId Id of the raffle /// @dev The operator can cancel the raffle. The NFT is sent back to the seller /// The raised funds are send to the destination wallet. The buyers will /// be refunded offchain in the metawin wallet function cancelRaffle( uint256 _raffleId ) external virtual onlyRole(OPERATOR_ROLE) {} /// @param _raffleId Id of the raffle function transferRemainingFunds( uint256 _raffleId ) external onlyRole(OPERATOR_ROLE) { EntryInfoStruct storage entryInfo = rafflesEntryInfo[_raffleId]; require( entryInfo.status == STATUS.CANCEL_REQUESTED || entryInfo.status == STATUS.CANCELLED, "Wrong status" ); entryInfo.status = STATUS.CANCELLED; (bool sent, ) = destinationWallet.call{value: entryInfo.amountRaised}( "" ); require(sent, "Fail send Eth to MW"); emit RemainingFundsTransferred(_raffleId, entryInfo.amountRaised); entryInfo.amountRaised = 0; } /// @param _raffleId Id of the raffle /// @return array of entries bougth of that particular raffle function getEntriesBought( uint256 _raffleId ) external view returns (EntriesBought[] memory) { return entriesList[_raffleId]; } /// @dev for different reasons player entries should be void /// this has a cost in gas, but this makes cheaper in gas the callback from chainlink /// This method has to be called for every raffle of the blacklisted player /// @param _raffleId Id of the raffle /// @param entriesToCancel array that contains the index of the entries to cancel. 0 based /// @param _player player who owns the entry to be voided function cancelEntry( uint256 _raffleId, uint256[] calldata entriesToCancel, address _player ) external onlyRole(OPERATOR_ROLE) { uint256 totalEntriesBoughtCancelled; for (uint256 i; i < entriesToCancel.length; ) { unchecked { EntriesBought storage entry = entriesList[_raffleId][ entriesToCancel[i] + 1 ]; require( entry.player == _player, "Entry did not belong to player" ); entry.player = address(0); //Set the entry as if the player is blacklisted uint256 previousTotalEntriesLength; if (entriesToCancel[i] == 0) previousTotalEntriesLength = 0; else previousTotalEntriesLength = entriesList[_raffleId][ entriesToCancel[i] ].currentEntriesLength; totalEntriesBoughtCancelled += entry.currentEntriesLength - previousTotalEntriesLength; ++i; } } emit EntryCancelled(_raffleId, totalEntriesBoughtCancelled, _player); } function getRafflesEntryInfo( uint256 _raffleId ) public view returns (EntryInfoStruct memory) { return rafflesEntryInfo[_raffleId]; } function transferNFTTo( address prizeAddress, uint256 prizeNumber, address receptor ) internal { IERC721 _asset = IERC721(prizeAddress); _asset.transferFrom(address(this), receptor, prizeNumber); } function transferETHTo(uint256 prizeNumber, address receptor) internal { (bool sentPrize, ) = receptor.call{value: prizeNumber}(""); require(sentPrize, "Failed to send Ether"); } function transferERC20To( address prizeAddress, uint256 prizeNumber, address receptor ) internal { IERC20 _asset = IERC20(prizeAddress); _asset.transfer(receptor, prizeNumber); } /// @param _raffleId Id of the raffle /// @dev The operator can cancel the raffle. The NFT is sent back to the seller /// The raised funds are send to the destination wallet. The buyers will /// be refunded offchain in the metawin wallet function _cancelRaffleActions(uint256 _raffleId, uint48 _type) internal { RaffleStruct storage raffle = raffles[_raffleId]; EntryInfoStruct storage entryInfo = rafflesEntryInfo[_raffleId]; // Dont cancel twice, or cancel an already ended raffle //TODO: To save gas, check that it is in the correct status instead of checking all the wrong ones require( entryInfo.status == STATUS.ACCEPTED || entryInfo.status == STATUS.CREATED, "Wrong status" ); // only if the raffle is in accepted status the NFT is staked and could have entries sold if (entryInfo.status == STATUS.ACCEPTED) { if (_type == 0) // transfer nft to the owner transferNFTTo( raffle.prizeAddress, raffle.prizeNumber, raffle.seller ); if (_type == 1) // transfer ETH to the owner transferETHTo(raffle.prizeNumber, raffle.seller); if (_type == 2) // transfer ETH to the owner transferERC20To( raffle.prizeAddress, raffle.prizeNumber, raffle.seller ); } entryInfo.status = STATUS.CANCEL_REQUESTED; emit RaffleCancelled(_raffleId, entryInfo.amountRaised); } // The operator can call this method once they receive the event "RandomNumberCreated" // triggered by the VRF v1 consumer contract (RandomNumber.sol) /// @param _raffleId Id of the raffle /// @param _normalizedRandomNumber index of the array that contains the winner of the raffle. Generated by chainlink /// @notice it is the method that sets the winner and transfers funds and nft /// @dev called by Chainlink callback function transferPrizesAndFundsActions( uint256 _raffleId, uint256 _normalizedRandomNumber ) internal returns (RaffleStruct memory) { RaffleStruct storage raffle = raffles[_raffleId]; EntryInfoStruct storage entryInfo = rafflesEntryInfo[_raffleId]; // Only when the raffle has been asked to be closed and the platform require( entryInfo.status == STATUS.EARLY_CASHOUT || entryInfo.status == STATUS.CLOSING_REQUESTED, "Raffle in wrong status" ); raffle.randomNumber = _normalizedRandomNumber; raffle.winner = getWinnerAddressFromRandom( _raffleId, _normalizedRandomNumber ); entryInfo.status = STATUS.ENDED; uint256 amountForPlatform = (entryInfo.amountRaised * raffle.platformPercentage) / 10000; uint256 amountForSeller = entryInfo.amountRaised - amountForPlatform; // transfer amount (75%) to the seller. (bool sent, ) = raffle.seller.call{value: amountForSeller}(""); require(sent, "Failed to send Ether"); // transfer the amount to the platform (bool sent2, ) = destinationWallet.call{value: amountForPlatform}(""); require(sent2, "Failed send Eth to MW"); emit FeeTransferredToPlatform(_raffleId, amountForPlatform); emit RaffleEnded( _raffleId, raffle.winner, entryInfo.amountRaised, _normalizedRandomNumber ); return raffle; } function saveEntryInfo( uint48 _walletsCapPerUser, ENTRY_TYPE _entryType, address[] calldata _whitelist, uint256 _raffleId ) internal virtual {} /// @notice Creates the raffle in the data structures of the contract /// @dev Saves the raffle struct. Creates the packages with the price and amount of entries in the priceStructure struct. /// Saves the desired and required funds, and to avoid the first player to pay extra gas, the entries data structure is created and deleted. /// It is an internal method that will be called by the createRaffle method of the correspondent competition contract /// @param _desiredFundsInWeis Funds in wais the seller wants /// @param _prizeAddress if the prize is an NFT or an ERC20, the address of the prize. If the prize is ETH, will be address(0) /// @param _prizeNumber if the prize is an NFT, the token Id of the NFT. If the prize is an ERC20 the number of tokens of the prize. If the prize /// is ETH, the amount in weis of the prize. /// @param _minimumFundsInWeis The mininum amount required for the raffle to set a winner /// @param _prices array of elements of type PriceStructure that contains the packages with prize (in weis) and amount of entries used in the raffle /// @param _commissionInBasicPoints percentage in basic points the platform will make. /// @param _entryType Obsolete param (used for the hamburger system from Valerio), used only for compatibility porpouses. function createRaffleActions( uint128 _desiredFundsInWeis, address _prizeAddress, uint256 _prizeNumber, uint128 _minimumFundsInWeis, PriceStructure[] calldata _prices, uint48 _commissionInBasicPoints, ENTRY_TYPE _entryType ) internal { RaffleStruct memory raffle = RaffleStruct({ prizeAddress: _prizeAddress, prizeNumber: _prizeNumber, winner: address(0), randomNumber: 0, seller: address(0), platformPercentage: _commissionInBasicPoints }); raffles.push(raffle); uint256 idRaffle = raffles.length - 1; if (_prices.length == 0) revert CreateRaffleError("No prices"); for (uint256 i; i < _prices.length; ++i) { if (_prices[i].numEntries == 0) revert CreateRaffleError("numEntries is 0"); PriceStructure memory p = PriceStructure({ id: uint48(idRaffle), numEntries: _prices[i].numEntries, price: _prices[i].price }); pricesList[_prices[i].id] = p; } fundingList[raffles.length - 1] = FundingStructure({ minimumFundsInWeis: _minimumFundsInWeis, desiredFundsInWeis: _desiredFundsInWeis }); emit RaffleCreated(raffles.length - 1, _prizeAddress, _prizeNumber); // Initialize the entries list array, by adding a player and removing it EntriesBought memory entryBought = EntriesBought({ player: msg.sender, currentEntriesLength: uint48(1) }); entriesList[idRaffle].push(entryBought); delete entriesList[idRaffle][0]; } function saveEntryInfoForMulti( address[] calldata _whitelist, uint48 _walletsCap, uint256 _raffleId ) internal { bool requireWhitelisting = false; uint256 whitelistLength = _whitelist.length; if (whitelistLength > 0) { requireWhitelisting = true; for (uint256 i; i <= whitelistLength - 1; ++i) { bytes32 key = keccak256(abi.encode(_whitelist[i], _raffleId)); whitelistCollections[key] = true; } } EntryInfoStruct memory entryInfo = EntryInfoStruct({ status: STATUS.CREATED, amountRaised: 0, entriesLength: 0, requireWhitelisting: requireWhitelisting, walletsCap: _walletsCap }); rafflesEntryInfo.push(entryInfo); } /** * @dev Reverts the status of a raffle from CLOSING_REQUESTED back to ACCEPTED. * This allows the raffle to remain open for further actions such as a redraw. * Useful in avoiding funds becoming stuck in the event of a failed draw. * @param raffleId The identifier of the raffle to revert the closing status for. * @notice Can only be called by users with the OPERATOR_ROLE. * Emits a RaffleStatusUpdated event upon successful status update. * @notice Ensures the raffle is currently in CLOSING_REQUESTED status before reverting. */ function revertCloseRequested(uint256 raffleId) public onlyRole(OPERATOR_ROLE) { require(rafflesEntryInfo[raffleId].status == STATUS.CLOSING_REQUESTED, "Raffle is not in close requested state"); rafflesEntryInfo[raffleId].status = STATUS.ACCEPTED; emit RaffleStatusUpdated(raffleId, STATUS.ACCEPTED); } }
//SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import "@openzeppelin/contracts/access/AccessControl.sol"; //import "@chainlink/contracts/src/v0.8/VRFConsumerBase.sol"; import "../interfaces/IDelegationRegistry.sol"; import "./MinimalConstants.sol"; abstract contract Constants is AccessControl, MinimalConstants { ////////// DELEGATE:CASH /////////////// IDelegationRegistry reg; // Main raffle data struct struct RaffleStruct { uint256 prizeNumber; // number (can be a percentage, an id, an amount, etc. depending on the competition) uint48 platformPercentage; // percentage of the funds raised that goes to the platform address prizeAddress; // address of the prize address winner; // address of thed winner of the raffle. Address(0) if no winner yet address seller; // address of the seller of the NFT uint256 randomNumber; // normalized (0-Entries array size) random number generated by the VRF } // The main structure is an array of raffles RaffleStruct[] public raffles; struct EntryInfoStruct { bool requireWhitelisting; STATUS status; // status of the raffle. Can be created, accepted, ended, etc uint48 walletsCap; uint48 entriesLength; // to easy frontend, the length of the entries array is saved here uint128 amountRaised; // funds raised so far in wei } // The main structure is an array of raffles EntryInfoStruct[] public rafflesEntryInfo; // All the different status a rafVRFCoordinatorfle can have enum STATUS { CREATED, // the operator creates the raffle ACCEPTED, // the seller stakes the nft for the raffle EARLY_CASHOUT, // the seller wants to cashout early CANCELLED, // the operator cancels the raffle and transfer the remaining funds after 30 days passes CLOSING_REQUESTED, // the operator requests to close the raffle and start the VRF ENDED, // the raffle is finished, and NFT and funds were transferred CANCEL_REQUESTED, // operator asks to cancel the raffle. Players has 30 days to ask for a refund WINNER_DETERMINED // the vrf sets a winner } // Event sent when the raffle is created by the operator event RaffleCreated( uint256 indexed raffleId, address indexed nftAddress, uint256 indexed nftId ); // Event sent when one or more entries are sold (info from the price structure) event EntrySold( uint256 indexed raffleId, address indexed buyer, uint256 currentSize, uint256 priceStructureId ); constructor() { _grantRole(OPERATOR_ROLE, 0x13503B622abC0bD30A7e9687057DF6E8c42Fb928); _grantRole(DEFAULT_ADMIN_ROLE, msg.sender); // the delegation registry addess is the same in all networks: // https://github.com/delegatecash/delegate-registry reg = IDelegationRegistry(0x00000000000076A84feF008CDAbe6409d2FE638B); } }
// 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: UNLICENSED pragma solidity ^0.8.22; import "../lib/MinimalConstants.sol"; import "@openzeppelin/contracts/access/AccessControl.sol"; import "@openzeppelin/contracts/utils/math/Math.sol"; import "../lib/VRFConsumerBaseV2.sol"; /// @title Raffles manager (lean, delegate.cash, single winner, nft gated with an nft from each whitelisted collection and a fixed amount of ETH as prize) /// @author Luis Pando /// @notice It consumes VRF v1 from Chainlink. It has the role /// "operator" that is the one used by a backend app to make some calls /// @dev It saves in an ordered array the player wallet and the current /// entries count. So buying entries has a complexity of O(1) /// For calculating the winner, from the huge random number generated by Chainlink /// a normalized random is generated by using the module method, adding 1 to have /// a random from 1 to entriesCount. /// So next step is to perform a binary search on the ordered array to get the /// player O(log n) /// Example: /// 0 -> { 1, player1} as player1 buys 1 entry /// 1 -> {51, player2} as player2 buys 50 entries /// 2 -> {52, player3} as player3 buys 1 entry /// 3 -> {53, player4} as player4 buys 1 entry /// 4 -> {153, player5} as player5 buys 100 entries /// So the setWinner method performs a binary search on that sorted array to get the upper bound. /// If the random number generated is 150, the winner is player5. If the random number is 20, winner is player2 abstract contract MinimalBase is AccessControl, MinimalConstants, VRFConsumerBaseV2 { constructor( address _vrfCoordinator, bytes32 _keyHash, uint64 _subId, uint16 _minimumRequestConfirmations, uint32 _callbackGasLimit, uint32 _numWords ) payable VRFConsumerBaseV2(_vrfCoordinator) { _grantRole(OPERATOR_ROLE, 0x13503B622abC0bD30A7e9687057DF6E8c42Fb928); _grantRole(DEFAULT_ADMIN_ROLE, msg.sender); keyHash = _keyHash; subId = _subId; minimumRequestConfirmations = _minimumRequestConfirmations; callbackGasLimit = _callbackGasLimit; numWords = _numWords; vrfCoordinator = VRFCoordinatorV2Interface(_vrfCoordinator); } function _callVRFAndGetRequestId() internal returns (uint256 requestId) { // keyhash, subid, minConfirmations, callbackGasLimit, numWords uint256 result = vrfCoordinator.requestRandomWords(keyHash, subId, minimumRequestConfirmations, callbackGasLimit, numWords); return result; } /// @dev this is the method that will be called by the smart contract to get a random number /// @param _id Id of the raffle /// @param _entriesSize length of the entries array of that raffle /// @param _requestId id generated by Chainlink function _getRandomNumber( uint256 _id, uint256 _entriesSize, uint256 _requestId ) internal { chainlinkRaffleInfo[_requestId] = RaffleInfo({ id: _id, size: _entriesSize }); } // helper method to get the winner address of a raffle /// @param _raffleId Id of the raffle /// @param _normalizedRandomNumber Generated by chainlink /// @return the wallet that won the raffle /// @dev Uses a binary search on the sorted array to retreive the winner /// but if the winner candidate is blacklisted, loop through the left looking for /// a candidate not blacklisted function getWinnerAddressFromRandom( uint256 _raffleId, uint256 _normalizedRandomNumber ) public virtual view returns (address) { uint256 position = _findUpperBound( entriesList[_raffleId], _normalizedRandomNumber ); address candidate = entriesList[_raffleId][position].player; // general case if (candidate != address(0)) return candidate; // special case. The user is blacklisted, so try next on the left until find a non-blacklisted else { bool ended = false; uint256 i = position; while ( ended == false && entriesList[_raffleId][i].player == address(0) ) { if (i == 0) i = entriesList[_raffleId].length - 1; else i = i - 1; // we came to the beginning without finding a non blacklisted player if (i == position) ended == true; } require(!ended, "All users blacklisted"); return entriesList[_raffleId][i].player; } } /// @param array sorted array of EntriesBought. CurrentEntriesLength is the numeric field used to sort /// @param element uint256 to find. Goes from 1 to entriesLength /// @dev based on openzeppelin code (v4.0), modified to use an array of EntriesBought /// Searches a sorted array and returns the first index that contains a value greater or equal to element. /// If no such index exists (i.e. all values in the array are strictly less than element), the array length is returned. Time complexity O(log n). /// array is expected to be sorted in ascending order, and to contain no repeated elements. /// https://docs.openzeppelin.com/contracts/3.x/api/utils#Arrays-_findUpperBound-uint256---uint256- function _findUpperBound( EntriesBought[] storage array, uint256 element ) internal view returns (uint256) { if (array.length == 0) { return 0; } uint256 low = 0; uint256 high = array.length; while (low < high) { uint256 mid = Math.average(low, high); // Note that mid will always be strictly less than high (i.e. it will be a valid array index) // because Math.average rounds down (it does integer division with truncation). if (array[mid].currentEntriesLength > element) { high = mid; } else { low = mid + 1; } } // At this point `low` is the exclusive upper bound. We will return the inclusive upper bound. if (low > 0 && array[low - 1].currentEntriesLength == element) { return low - 1; } else { return low; } } }
//SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import "../lib/interfaces/VRFCoordinatorV2Interface.sol"; abstract contract MinimalConstants { ////////// CHAINLINK VRF v2 ///////////////// bytes32 internal immutable keyHash; // chainlink uint64 internal immutable subId; // chainlink subscription id for the random number uint16 internal immutable minimumRequestConfirmations; // the minimum amount of blocks to wait for the random number uint32 internal immutable callbackGasLimit; // the gas limit for the callback uint32 internal immutable numWords; // the number of words to generate for the random number VRFCoordinatorV2Interface internal immutable vrfCoordinator; // VRF coordinator contract struct RandomResult { uint256 randomNumber; // random number generated by chainlink. uint256 nomalizedRandomNumber; // random number % entriesLength + 1. So between 1 and entries.length } // event sent when the random number is generated by the VRF event RandomNumberCreated( uint256 indexed idFromMetawin, uint256 randomNumber, uint256 normalizedRandomNumber ); struct RaffleInfo { uint256 id; // raffleId uint256 size; // length of the entries array of that raffle } mapping(uint256 => RandomResult) public requests; // map the requestId created by chainlink with the raffle info passed as param when calling _getRandomNumber() mapping(uint256 => RaffleInfo) public chainlinkRaffleInfo; /////////////// END CHAINKINK VRF V2 ////////////// error EntryNotAllowed(string errorType); error CreateRaffleError(string errorType); // Event sent when the owner of the nft stakes it for the raffle event RaffleStarted(uint256 indexed raffleId, address indexed seller); // Event sent when the raffle is finished (either early cashout or successful completion) event RaffleEnded( uint256 indexed raffleId, address indexed winner, uint256 amountRaised, uint256 randomNumber ); // Event sent when a free entry is added by the operator event FreeEntry( uint256 indexed raffleId, address[] buyer, uint256 amount, uint256 currentSize ); // Event sent when a raffle is asked to cancel by the operator event RaffleCancelled(uint256 indexed raffleId, uint256 amountRaised); // The raffle is closed successfully and the platform receives the fee event FeeTransferredToPlatform( uint256 indexed raffleId, uint256 amountTransferred ); // When the raffle is asked to be cancelled and 30 days have passed, the operator can call a method // to transfer the remaining funds and this event is emitted event RemainingFundsTransferred( uint256 indexed raffleId, uint256 amountInWeis ); // When the raffle is asked to be cancelled and 30 days have not passed yet, the players can call a // method to refund the amount spent on the raffle and this event is emitted event Refund( uint256 indexed raffleId, uint256 amountInWeis, address indexed player ); event EarlyCashoutTriggered(uint256 indexed raffleId, uint256 amountRaised); event SetWinnerTriggered(uint256 indexed raffleId, uint256 amountRaised); // Emitted when an entry is cancelled event EntryCancelled( uint256 indexed raffleId, uint256 amountOfEntriesCanceled, address player ); struct PriceStructure { uint48 id; uint48 numEntries; uint168 price; } mapping(uint256 => PriceStructure) public pricesList; // Every raffle has a funding structure. struct FundingStructure { uint128 minimumFundsInWeis; uint128 desiredFundsInWeis; } mapping(uint256 => FundingStructure) public fundingList; // In order to calculate the winner, in this struct is saved for each bought the data struct EntriesBought { uint48 currentEntriesLength; // current amount of entries bought in the raffle address player; // wallet address of the player } // every raffle has a sorted array of EntriesBought. Each element is created when calling // either buyEntry or giveBatchEntriesForFree mapping(uint256 => EntriesBought[]) public entriesList; // Map with the player wallets linked to a particular raffle + nft mapping(bytes32 => address) public requiredNFTWallets; mapping(bytes32 => uint48) public walletsCap; // key = collection address + raffleID mapping(bytes32 => bool) public whitelistCollections; // 31.07.23 MDA1819 mapping(bytes32 => bool) public freeEntriesPerWallet; struct NFTIdUsed { address collection; uint256 tokenId; } enum ENTRY_TYPE { ONLY_DIRECTLY, ONLY_EXTERNAL_CONTRACT, MIXED } // The operator role is operated by a backend application bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR"); // requested by Hamburger. Role for the buy method of the hamburger (only that contract) bytes32 public constant MINTERCONTRACT_ROLE = keccak256("MINTERCONTRACT"); // address of the wallet controlled by the platform that will receive the platform fee address payable public destinationWallet = payable(0x52a032cF59eA274f9D745f29b6D514fe95Ba192D); }
// 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); // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i 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 */ // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore 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); } }
{ "optimizer": { "enabled": true, "runs": 200 }, "evmVersion": "paris", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
[{"inputs":[{"internalType":"address","name":"_vrfCoordinator","type":"address"},{"internalType":"bytes32","name":"_keyHash","type":"bytes32"},{"internalType":"uint64","name":"_subId","type":"uint64"},{"internalType":"uint16","name":"_minimumRequestConfirmations","type":"uint16"},{"internalType":"uint32","name":"_callbackGasLimit","type":"uint32"},{"internalType":"uint32","name":"_numWords","type":"uint32"}],"stateMutability":"payable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"string","name":"errorType","type":"string"}],"name":"CreateRaffleError","type":"error"},{"inputs":[{"internalType":"string","name":"errorType","type":"string"}],"name":"EntryNotAllowed","type":"error"},{"inputs":[{"internalType":"address","name":"have","type":"address"},{"internalType":"address","name":"want","type":"address"}],"name":"OnlyCoordinatorCanFulfill","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountRaised","type":"uint256"}],"name":"EarlyCashoutTriggered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfEntriesCanceled","type":"uint256"},{"indexed":false,"internalType":"address","name":"player","type":"address"}],"name":"EntryCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":true,"internalType":"address","name":"buyer","type":"address"},{"indexed":false,"internalType":"uint256","name":"currentSize","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"priceStructureId","type":"uint256"}],"name":"EntrySold","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountTransferred","type":"uint256"}],"name":"FeeTransferredToPlatform","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":false,"internalType":"address[]","name":"buyer","type":"address[]"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"currentSize","type":"uint256"}],"name":"FreeEntry","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountRaised","type":"uint256"}],"name":"RaffleCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":true,"internalType":"address","name":"nftAddress","type":"address"},{"indexed":true,"internalType":"uint256","name":"nftId","type":"uint256"}],"name":"RaffleCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":true,"internalType":"address","name":"winner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountRaised","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"randomNumber","type":"uint256"}],"name":"RaffleEnded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":true,"internalType":"address","name":"seller","type":"address"}],"name":"RaffleStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":false,"internalType":"enum Constants.STATUS","name":"newStatus","type":"uint8"}],"name":"RaffleStatusUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"idFromMetawin","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"randomNumber","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"normalizedRandomNumber","type":"uint256"}],"name":"RandomNumberCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountInWeis","type":"uint256"},{"indexed":true,"internalType":"address","name":"player","type":"address"}],"name":"Refund","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountInWeis","type":"uint256"}],"name":"RemainingFundsTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountRaised","type":"uint256"}],"name":"SetWinnerTriggered","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINTERCONTRACT_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OPERATOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_raffleId","type":"uint256"},{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"buyEntry","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_raffleId","type":"uint256"},{"internalType":"uint256[]","name":"entriesToCancel","type":"uint256[]"},{"internalType":"address","name":"_player","type":"address"}],"name":"cancelEntry","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_raffleId","type":"uint256"}],"name":"cancelRaffle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"chainlinkRaffleInfo","outputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"size","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"_desiredFundsInWeis","type":"uint128"},{"internalType":"uint256","name":"_prizeNumber","type":"uint256"},{"internalType":"uint128","name":"_minimumFundsInWeis","type":"uint128"},{"components":[{"internalType":"uint48","name":"id","type":"uint48"},{"internalType":"uint48","name":"numEntries","type":"uint48"},{"internalType":"uint168","name":"price","type":"uint168"}],"internalType":"struct MinimalConstants.PriceStructure[]","name":"_prices","type":"tuple[]"},{"internalType":"uint48","name":"_commissionInBasicPoints","type":"uint48"},{"internalType":"enum MinimalConstants.ENTRY_TYPE","name":"_entryType","type":"uint8"}],"name":"createRaffle","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"destinationWallet","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"entriesList","outputs":[{"internalType":"uint48","name":"currentEntriesLength","type":"uint48"},{"internalType":"address","name":"player","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"freeEntriesPerWallet","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"fundingList","outputs":[{"internalType":"uint128","name":"minimumFundsInWeis","type":"uint128"},{"internalType":"uint128","name":"desiredFundsInWeis","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_raffleId","type":"uint256"}],"name":"getEntriesBought","outputs":[{"components":[{"internalType":"uint48","name":"currentEntriesLength","type":"uint48"},{"internalType":"address","name":"player","type":"address"}],"internalType":"struct MinimalConstants.EntriesBought[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_raffleId","type":"uint256"}],"name":"getRafflesEntryInfo","outputs":[{"components":[{"internalType":"bool","name":"requireWhitelisting","type":"bool"},{"internalType":"enum Constants.STATUS","name":"status","type":"uint8"},{"internalType":"uint48","name":"walletsCap","type":"uint48"},{"internalType":"uint48","name":"entriesLength","type":"uint48"},{"internalType":"uint128","name":"amountRaised","type":"uint128"}],"internalType":"struct Constants.EntryInfoStruct","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_raffleId","type":"uint256"},{"internalType":"uint256","name":"_normalizedRandomNumber","type":"uint256"}],"name":"getWinnerAddressFromRandom","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_raffleId","type":"uint256"},{"internalType":"address[]","name":"_freePlayers","type":"address[]"}],"name":"giveBatchEntriesForFree","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"pricesList","outputs":[{"internalType":"uint48","name":"id","type":"uint48"},{"internalType":"uint48","name":"numEntries","type":"uint48"},{"internalType":"uint168","name":"price","type":"uint168"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"raffles","outputs":[{"internalType":"uint256","name":"prizeNumber","type":"uint256"},{"internalType":"uint48","name":"platformPercentage","type":"uint48"},{"internalType":"address","name":"prizeAddress","type":"address"},{"internalType":"address","name":"winner","type":"address"},{"internalType":"address","name":"seller","type":"address"},{"internalType":"uint256","name":"randomNumber","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rafflesEntryInfo","outputs":[{"internalType":"bool","name":"requireWhitelisting","type":"bool"},{"internalType":"enum Constants.STATUS","name":"status","type":"uint8"},{"internalType":"uint48","name":"walletsCap","type":"uint48"},{"internalType":"uint48","name":"entriesLength","type":"uint48"},{"internalType":"uint128","name":"amountRaised","type":"uint128"}],"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":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"requests","outputs":[{"internalType":"uint256","name":"randomNumber","type":"uint256"},{"internalType":"uint256","name":"nomalizedRandomNumber","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"requiredNFTWallets","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"raffleId","type":"uint256"}],"name":"revertCloseRequested","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"_newAddress","type":"address"}],"name":"setDestinationAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_raffleId","type":"uint256"}],"name":"setWinner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_raffleId","type":"uint256"}],"name":"stakeETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_raffleId","type":"uint256"}],"name":"transferRemainingFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"walletsCap","outputs":[{"internalType":"uint48","name":"","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"whitelistCollections","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
6101606040819052600a80546001600160a01b0319167352a032cf59ea274f9d745f29b6d514fe95ba192d17905562003c6b388190039081908339810160408190526200004c9162000216565b858585858585858585858585856200008860008051602062003c4b8339815191527313503b622abc0bd30a7e9687057df6e8c42fb9286200014d565b50620000966000336200014d565b50600b80546001600160a01b0319166d76a84fef008cdabe6409d2fe638b1790556001600160a01b031661014052620000f360008051602062003c4b8339815191527313503b622abc0bd30a7e9687057df6e8c42fb9286200014d565b50620001016000336200014d565b506080949094526001600160401b0390921660a05261ffff1660c05263ffffffff90811660e05216610100526001600160a01b03166101205250620002b29a5050505050505050505050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16620001f2576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620001a93390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001620001f6565b5060005b92915050565b805163ffffffff811681146200021157600080fd5b919050565b60008060008060008060c087890312156200023057600080fd5b86516001600160a01b03811681146200024857600080fd5b6020880151604089015191975095506001600160401b03811681146200026d57600080fd5b606088015190945061ffff811681146200028657600080fd5b92506200029660808801620001fc565b9150620002a660a08801620001fc565b90509295509295509295565b60805160a05160c05160e0516101005161012051610140516139376200031460003960008181610a220152610a6401526000611abb01526000611a8701526000611a5f01526000611a3301526000611a09015260006119da01526139376000f3fe6080604052600436106102045760003560e01c806353b7a59b1161011857806393a75d02116100a0578063d649214c1161006f578063d649214c1461074d578063ddba6e6b1461076d578063f3691455146107ec578063f5b541a61461080c578063f720e7081461082e57600080fd5b806393a75d02146106b7578063a217fddf146106e4578063cf7874a3146106f9578063d547741f1461072d57600080fd5b80637c903fc0116100e75780637c903fc0146105ca5780637fa4cacb146105fe57806381d12c581461061e5780638499e1b21461066757806391d148541461069757600080fd5b806353b7a59b146105145780635d4bc0ce146105345780635fba3171146105975780636ecc20da146105b757600080fd5b8063248a9ca31161019b578063365e36581161016a578063365e36581461044657806336734e341461047357806336a418bf146104935780633a3956c2146104c35780634006efe0146104f457600080fd5b8063248a9ca3146103b65780632f2ff15d146103e6578063317f30591461040657806336568abe1461042657600080fd5b806316e17bf1116101d757806316e17bf1146103075780631a0187f5146103355780631fe543e31461038357806323685496146103a357600080fd5b8063013805c51461020957806301ffc9a714610254578063039be558146102845780630df71602146102e5575b600080fd5b34801561021557600080fd5b50610229610224366004613199565b61087a565b6040805165ffffffffffff90931683526001600160a01b039091166020830152015b60405180910390f35b34801561026057600080fd5b5061027461026f3660046131bb565b6108c2565b604051901515815260200161024b565b34801561029057600080fd5b506102c561029f3660046131e5565b6004602052600090815260409020546001600160801b0380821691600160801b90041682565b604080516001600160801b0393841681529290911660208301520161024b565b3480156102f157600080fd5b506103056103003660046131e5565b6108f9565b005b34801561031357600080fd5b5061032761032236600461323f565b61096e565b60405190815260200161024b565b34801561034157600080fd5b5061036b6103503660046131e5565b6006602052600090815260409020546001600160a01b031681565b6040516001600160a01b03909116815260200161024b565b34801561038f57600080fd5b5061030561039e36600461336c565b610a17565b6103056103b1366004613199565b610a9f565b3480156103c257600080fd5b506103276103d13660046131e5565b60009081526020819052604090206001015490565b3480156103f257600080fd5b50610305610401366004613423565b610abd565b34801561041257600080fd5b506103056104213660046131e5565b610ae2565b34801561043257600080fd5b50610305610441366004613423565b610caf565b34801561045257600080fd5b506104666104613660046131e5565b610ce2565b60405161024b9190613453565b34801561047f57600080fd5b5061030561048e3660046134b3565b610d70565b34801561049f57600080fd5b506102746104ae3660046131e5565b60086020526000908152604090205460ff1681565b3480156104cf57600080fd5b506104e36104de3660046131e5565b610f7f565b60405161024b959493929190613582565b34801561050057600080fd5b5061030561050f3660046131e5565b610fd8565b34801561052057600080fd5b50600a5461036b906001600160a01b031681565b34801561054057600080fd5b5061055461054f3660046131e5565b611104565b6040805196875265ffffffffffff90951660208701526001600160a01b0393841694860194909452908216606085015216608083015260a082015260c00161024b565b3480156105a357600080fd5b506103056105b23660046131e5565b611164565b6103056105c53660046131e5565b611187565b3480156105d657600080fd5b506103277fde5ee446972f4e39ab62c03aa34b2096680a875c3fdb3eb2f947cbb93341c05881565b34801561060a57600080fd5b506103056106193660046135c8565b6112c2565b34801561062a57600080fd5b506106526106393660046131e5565b6001602081905260009182526040909120805491015482565b6040805192835260208301919091520161024b565b34801561067357600080fd5b506102746106823660046131e5565b60096020526000908152604090205460ff1681565b3480156106a357600080fd5b506102746106b2366004613423565b6112f0565b3480156106c357600080fd5b506106d76106d23660046131e5565b611319565b60405161024b91906135e5565b3480156106f057600080fd5b50610327600081565b34801561070557600080fd5b506106526107143660046131e5565b6002602052600090815260409020805460019091015482565b34801561073957600080fd5b50610305610748366004613423565b6113ed565b34801561075957600080fd5b5061030561076836600461363e565b611412565b34801561077957600080fd5b506107be6107883660046131e5565b6003602052600090815260409020805460019091015465ffffffffffff80831692600160301b900416906001600160a81b031683565b6040805165ffffffffffff94851681529390921660208401526001600160a81b03169082015260600161024b565b3480156107f857600080fd5b5061036b610807366004613199565b6115c6565b34801561081857600080fd5b506103276000805160206138e283398151915281565b34801561083a57600080fd5b506108636108493660046131e5565b60076020526000908152604090205465ffffffffffff1681565b60405165ffffffffffff909116815260200161024b565b6005602052816000526040600020818154811061089657600080fd5b60009182526020909120015465ffffffffffff81169250600160301b90046001600160a01b0316905082565b60006001600160e01b03198216637965db0b60e01b14806108f357506301ffc9a760e01b6001600160e01b03198316145b92915050565b6000805160206138e28339815191526109118161174d565b600061091c8361175a565b905060006109286119cb565b905061096884836060015165ffffffffffff1683604080518082018252938452602080850193845260009283526002905290209151825551600190910155565b50505050565b60006000805160206138e28339815191526109888161174d565b6113888465ffffffffffff1611156109de57604051636b221d4560e11b81526020600482015260136024820152720c6dedadad2e6e6d2dedc40e8dede40d0d2ced606b1b60448201526064015b60405180910390fd5b6109ef8960008a8a8a8a8a8a611b28565b6109f7611fd7565b600c54600090610a09906001906136e6565b9a9950505050505050505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610a915760405163073e64fd60e21b81523360048201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001660248201526044016109d5565b610a9b82826120ee565b5050565b6000610aab838361220f565b9050610ab88184846126bb565b505050565b600082815260208190526040902060010154610ad88161174d565b610968838361280a565b6000805160206138e2833981519152610afa8161174d565b6000600d8381548110610b0f57610b0f6136f9565b6000918252602090912001905060068154610100900460ff166007811115610b3957610b3961354a565b1480610b5f575060038154610100900460ff166007811115610b5d57610b5d61354a565b145b610b9a5760405162461bcd60e51b815260206004820152600c60248201526b57726f6e672073746174757360a01b60448201526064016109d5565b805461ff00191661030017808255600a546040516000926001600160a01b0390921691600160701b90046001600160801b0316908381818185875af1925050503d8060008114610c06576040519150601f19603f3d011682016040523d82523d6000602084013e610c0b565b606091505b5050905080610c525760405162461bcd60e51b81526020600482015260136024820152724661696c2073656e642045746820746f204d5760681b60448201526064016109d5565b8154604051600160701b9091046001600160801b0316815284907fcdef6558dae40f2699846eedf449462daab85b1224ad7f077569ba91aaa949259060200160405180910390a2508054600160701b600160f01b03191690555050565b6001600160a01b0381163314610cd85760405163334bd91960e11b815260040160405180910390fd5b610ab8828261289c565b606060056000838152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015610d65576000848152602090819020604080518082019091529084015465ffffffffffff81168252600160301b90046001600160a01b031681830152825260019092019101610d17565b505050509050919050565b6000805160206138e2833981519152610d888161174d565b6000600d8481548110610d9d57610d9d6136f9565b6000918252602090912001905060018154610100900460ff166007811115610dc757610dc761354a565b14610e145760405162461bcd60e51b815260206004820152601960248201527f526166666c65206973206e6f7420696e2061636365707465640000000000000060448201526064016109d5565b82516000805b82811015610ef0576000868281518110610e3657610e366136f9565b6020026020010151905060006040518060400160405280848860000160089054906101000a900465ffffffffffff1665ffffffffffff16610e77919061370f565b610e8290600161370f565b65ffffffffffff90811682526001600160a01b0394851660209283015260008c81526005835260408120805460018181018355918352918490208551920180549590940151909616600160301b026001600160d01b0319909416911617919091179055509182019101610e1a565b508254610f0d908290600160401b900465ffffffffffff16613722565b835465ffffffffffff60401b1916600160401b65ffffffffffff92831681029190911780865560405189937f4da4f5fab0816c65315b6f5d15f879f96b98661133d7b3787788f291367604fb93610f6f938b9389939290910490911690613748565b60405180910390a2505050505050565b600d8181548110610f8f57600080fd5b60009182526020909120015460ff80821692506101008204169065ffffffffffff620100008204811691600160401b8104909116906001600160801b03600160701b9091041685565b6000805160206138e2833981519152610ff08161174d565b6004600d8381548110611005576110056136f9565b600091825260209091200154610100900460ff16600781111561102a5761102a61354a565b146110865760405162461bcd60e51b815260206004820152602660248201527f526166666c65206973206e6f7420696e20636c6f73652072657175657374656460448201526520737461746560d01b60648201526084016109d5565b6001600d838154811061109b5761109b6136f9565b6000918252602090912001805461ff0019166101008360078111156110c2576110c261354a565b0217905550817fc1191e7178b58ad510709587719f39ec315fa79e81ee7ba5c5ef3c894e94a65160016040516110f891906137ad565b60405180910390a25050565b600c818154811061111457600080fd5b60009182526020909120600590910201805460018201546002830154600384015460049094015492945065ffffffffffff8216936001600160a01b03600160301b90930483169391831692169086565b6000805160206138e283398151915261117c8161174d565b610a9b826001612907565b6000600d828154811061119c5761119c6136f9565b9060005260206000200190506000600c83815481106111bd576111bd6136f9565b60009182526020822060059091020191508254610100900460ff1660078111156111e9576111e961354a565b1461122b5760405162461bcd60e51b8152602060048201526012602482015271149859999b19481b9bdd0810d4915055115160721b60448201526064016109d5565b8054341461126e5760405162461bcd60e51b815260206004820152601060248201526f141c9a5e99481b9bdd081cdd185ad95960821b60448201526064016109d5565b815461ff0019166101001782556003810180546001600160a01b0319163390811790915560405184907f8bb509eedfd1c4847b0a8a2b4493cf2ebb9970dc367e477cd2a8523e212dc1db90600090a3505050565b60006112cd8161174d565b50600a80546001600160a01b0319166001600160a01b0392909216919091179055565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b6040805160a081018252600080825260208201819052918101829052606081018290526080810191909152600d8281548110611357576113576136f9565b60009182526020918290206040805160a081019091529101805460ff80821615158452929391929184019161010090910416600781111561139a5761139a61354a565b60078111156113ab576113ab61354a565b8152905465ffffffffffff62010000820481166020840152600160401b82041660408301526001600160801b03600160701b9091041660609091015292915050565b6000828152602081905260409020600101546114088161174d565b610968838361289c565b6000805160206138e283398151915261142a8161174d565b6000805b84811015611585576000878152600560205260408120878784818110611456576114566136f9565b9050602002013560010181548110611470576114706136f9565b600091825260209091200180549091506001600160a01b03868116600160301b90920416146114e15760405162461bcd60e51b815260206004820152601e60248201527f456e74727920646964206e6f742062656c6f6e6720746f20706c61796572000060448201526064016109d5565b80546601000000000000600160d01b03191681556000878784818110611509576115096136f9565b9050602002013560000361151f5750600061156d565b600089815260056020526040902088888581811061153f5761153f6136f9565b9050602002013581548110611556576115566136f9565b60009182526020909120015465ffffffffffff1690505b905465ffffffffffff1603919091019060010161142e565b50604080518281526001600160a01b038516602082015287917f2cca80c1af5abb202a642a502875436822768d733462843a7c3a902b0fad99d09101610f6f565b600082815260056020526040812081906115e09084612ae5565b60008581526005602052604081208054929350909183908110611605576116056136f9565b600091825260209091200154600160301b90046001600160a01b0316905080156116325791506108f39050565b6000825b8115801561167d5750600087815260056020526040812080548390811061165f5761165f6136f9565b600091825260209091200154600160301b90046001600160a01b0316145b156116b757806000036116ac576000878152600560205260409020546116a5906001906136e6565b9050611636565b6116a56001826136e6565b81156116fd5760405162461bcd60e51b8152602060048201526015602482015274105b1b081d5cd95c9cc8189b1858dadb1a5cdd1959605a1b60448201526064016109d5565b600087815260056020526040902080548290811061171d5761171d6136f9565b600091825260209091200154600160301b90046001600160a01b031694506108f39350505050565b505092915050565b6117578133612bbc565b50565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091526000600d838154811061179a5761179a6136f9565b60009182526020808320868452600490915260409092209101915060018254610100900460ff1660078111156117d2576117d261354a565b146118185760405162461bcd60e51b8152602060048201526016602482015275526166666c6520696e2077726f6e672073746174757360501b60448201526064016109d5565b805482546001600160801b03918216600160701b90910490911610156118805760405162461bcd60e51b815260206004820152601760248201527f4e6f7420656e6f7567682066756e64732072616973656400000000000000000060448201526064016109d5565b81548154600160701b9091046001600160801b03908116600160801b9092041611156118ee5760405162461bcd60e51b815260206004820152601860248201527f446573697265642066756e6473206e6f7420726169736564000000000000000060448201526064016109d5565b815461ff0019166104001780835560408051600160701b9092046001600160801b031682525185917ff2be214756d2fbc1e781d10809ddef33000009d805be55356bb348134ce21c68919081900360200190a26040805160a08101909152825460ff80821615158352849160208401916101009091041660078111156119765761197661354a565b60078111156119875761198761354a565b8152905465ffffffffffff62010000820481166020840152600160401b82041660408301526001600160801b03600160701b90910416606090910152949350505050565b6040516305d3b1d360e41b81527f0000000000000000000000000000000000000000000000000000000000000000600482015267ffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016602482015261ffff7f000000000000000000000000000000000000000000000000000000000000000016604482015263ffffffff7f0000000000000000000000000000000000000000000000000000000000000000811660648301527f000000000000000000000000000000000000000000000000000000000000000016608482015260009081906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690635d3b1d309060a4016020604051808303816000875af1158015611b04573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108f391906137bb565b6040805160c08101825287815265ffffffffffff808516602083019081526001600160a01b03808c169484019485526000606085018181526080860182815260a08701838152600c8054600181810183558287528a5160059092027fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c781019290925597517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c8820180549c518916600160301b026001600160d01b0319909d1691909a16179a909a1790975591517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c9890180549186166001600160a01b031992831617905590517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8ca890180549190951691161790925590517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8cb909501949094559054919291611c9691906136e6565b90506000859003611cd657604051636b221d4560e11b81526020600482015260096024820152684e6f2070726963657360b81b60448201526064016109d5565b60005b85811015611e8957868682818110611cf357611cf36136f9565b9050606002016020016020810190611d0b91906137d4565b65ffffffffffff16600003611d5557604051636b221d4560e11b815260206004820152600f60248201526e06e756d456e7472696573206973203608c1b60448201526064016109d5565b600060405180606001604052808465ffffffffffff168152602001898985818110611d8257611d826136f9565b9050606002016020016020810190611d9a91906137d4565b65ffffffffffff168152602001898985818110611db957611db96136f9565b9050606002016040016020810190611dd191906137ef565b6001600160a81b03169052905080600360008a8a86818110611df557611df56136f9565b611e0b92602060609092020190810191506137d4565b65ffffffffffff9081168252602080830193909352604091820160002084518154948601518316600160301b026bffffffffffffffffffffffff199095169216919091179290921782559190910151600191820180546001600160a81b039092166001600160a81b0319909216919091179055919091019050611cd9565b50604080518082019091526001600160801b0380891682528b166020820152600c54600490600090611ebd906001906136e6565b8152602080820192909252604001600020825192909101516001600160801b03908116600160801b029216919091179055600c5488906001600160a01b038b1690611f0a906001906136e6565b6040517f81781e053ec72aa8731479536c4da8f819ef3283d2c0dea5c4f0d938bed8489590600090a460408051808201825260018082523360208084019182526000868152600582529485208054938401815580865290852084519301805492516001600160a01b0316600160301b026001600160d01b031990931665ffffffffffff949094169390931791909117909155838352805491929091611fb157611fb16136f9565b600091825260209091200180546001600160d01b03191690555050505050505050505050565b6040805160a0810182526000808252602082018181529282018190526060820181905260808201819052600d8054600181018255915281517fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb5909101805491151560ff198316811782559351929384939192839161ff00191661ffff199091161761010083600781111561206d5761206d61354a565b02179055506040820151815460608401516080909401516dffffffffffffffffffffffff0000199091166201000065ffffffffffff9384160265ffffffffffff60401b191617600160401b929094169190910292909217600160701b600160f01b031916600160701b6001600160801b039093169290920291909117905550565b6000828152600260209081526040808320815180830190925280548252600101549181018290528351909291908490839061212b5761212b6136f9565b602002602001015161213d919061382e565b61214890600161370f565b9050600060405180604001604052808560008151811061216a5761216a6136f9565b602090810291909101810151825290810184905284516000908152600180835260408220845181559284015192019190915584518651929350917f7c40e661b8212d0c4f60ac6e6ebed99c28680c7b3ede5b82f3b0254543f62fca9187916121d4576121d46136f9565b6020026020010151846040516121f4929190918252602082015260400190565b60405180910390a282516122089083612bf5565b5050505050565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091523233146122815760405163efeb42cf60e01b8152602060048201526014602482015273139bc818dbdb9d1c9858dd1cc8185b1b1bddd95960621b60448201526064016109d5565b6000600d8481548110612296576122966136f9565b6000918252602090912001905060018154610100900460ff1660078111156122c0576122c061354a565b146123005760405163efeb42cf60e01b815260206004820152600f60248201526e139bdd081a5b881050d0d154151151608a1b60448201526064016109d5565b6000838152600360209081526040918290208251606081018452815465ffffffffffff808216808452600160301b90920416938201939093526001909101546001600160a81b03169281019290925285146123935760405163efeb42cf60e01b81526020600482015260126024820152711259081b9bdd081a5b881c9859999b19525960721b60448201526064016109d5565b602081015160408201516001600160a81b031634146123f55760405163efeb42cf60e01b815260206004820152601760248201527f6d73672e76616c7565206e6f742074686520707269636500000000000000000060448201526064016109d5565b81604001516001600160a81b03166000036124b7576040805133602082015290810187905260009060600160408051601f1981840301815291815281516020928301206000818152600990935291205490915060ff16151560010361249d5760405163efeb42cf60e01b815260206004820152601d60248201527f506c6179657220616c726561647920676f74206672656520656e74727900000060448201526064016109d5565b6000908152600960205260409020805460ff191660011790555b825460408051808201909152600160401b90910465ffffffffffff1690600090806124e28585613722565b65ffffffffffff90811682523360209283015260008b815260058352604081208054600181018255818352848320865191018054958701516001600160a01b0316600160301b026001600160d01b03199096169190941617939093179091558a815281549293509091612557576125576136f9565b600091825260209091200180546001600160d01b0319169055845434908690600e90612594908490600160701b90046001600160801b0316613842565b92506101000a8154816001600160801b0302191690836001600160801b0316021790555082826125c49190613722565b855465ffffffffffff60401b1916600160401b65ffffffffffff928316810291909117808855604080519290910490921681526020810189905233918a917fd746af8dc82f9bed98cea0fe0264eb1c3d2e5f7bcc77fc5efb429c79df407887910160405180910390a36040805160a08101909152855460ff80821615158352879160208401916101009091041660078111156126625761266261354a565b60078111156126735761267361354a565b8152905462010000810465ffffffffffff9081166020840152600160401b8204166040830152600160701b90046001600160801b031660609091015298975050505050505050565b604083015165ffffffffffff1615610ab8576000818152600360209081526040808320815160608082018452825465ffffffffffff8082168452600160301b90910481168387019081526001909401546001600160a81b03168386015284518087018a90523381870152855180820387018152920185528151918601919091208087526007909552948390205492880151915190949283169291909116906127639083613722565b65ffffffffffff1611156127b05760405163efeb42cf60e01b815260206004820152601360248201527215d85b1b195d08185b1c9958591e481d5cd959606a1b60448201526064016109d5565b602080840151600084815260079092526040909120546127d8919065ffffffffffff16613722565b600092835260076020526040909220805465ffffffffffff191665ffffffffffff909316929092179091555050505050565b600061281683836112f0565b612894576000838152602081815260408083206001600160a01b03861684529091529020805460ff1916600117905561284c3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016108f3565b5060006108f3565b60006128a883836112f0565b15612894576000838152602081815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45060016108f3565b6000600c838154811061291c5761291c6136f9565b906000526020600020906005020190506000600d8481548110612941576129416136f9565b6000918252602090912001905060018154610100900460ff16600781111561296b5761296b61354a565b1480612991575060008154610100900460ff16600781111561298f5761298f61354a565b145b6129cc5760405162461bcd60e51b815260206004820152600c60248201526b57726f6e672073746174757360a01b60448201526064016109d5565b60018154610100900460ff1660078111156129e9576129e961354a565b03612a8c578265ffffffffffff16600003612a2857600182015482546003840154612a28926001600160a01b03600160301b9091048116929116612c15565b8265ffffffffffff16600103612a525781546003830154612a5291906001600160a01b0316612c86565b8265ffffffffffff16600203612a8c57600182015482546003840154612a8c926001600160a01b03600160301b9091048116929116612d20565b805461ff0019166106001780825560408051600160701b9092046001600160801b031682525185917fd512a34b0f0618078770fcd85d974df1ab46a7882e8b3d45aa91764f4961aed2919081900360200190a250505050565b81546000908103612af8575060006108f3565b82546000905b80821015612b5d576000612b128383612d96565b905084868281548110612b2757612b276136f9565b60009182526020909120015465ffffffffffff161115612b4957809150612b57565b612b5481600161370f565b92505b50612afe565b600082118015612b9b57508385612b756001856136e6565b81548110612b8557612b856136f9565b60009182526020909120015465ffffffffffff16145b15612bb457612bab6001836136e6565b925050506108f3565b5090506108f3565b612bc682826112f0565b610a9b5760405163e2517d3f60e01b81526001600160a01b0382166004820152602481018390526044016109d5565b6000612c018383612db8565b9050610ab881600001518260600151612c86565b6040516323b872dd60e01b81523060048201526001600160a01b038281166024830152604482018490528491908216906323b872dd90606401600060405180830381600087803b158015612c6857600080fd5b505af1158015612c7c573d6000803e3d6000fd5b5050505050505050565b6000816001600160a01b03168360405160006040518083038185875af1925050503d8060008114612cd3576040519150601f19603f3d011682016040523d82523d6000602084013e612cd8565b606091505b5050905080610ab85760405162461bcd60e51b81526020600482015260146024820152732330b4b632b2103a379039b2b7321022ba3432b960611b60448201526064016109d5565b60405163a9059cbb60e01b81526001600160a01b0382811660048301526024820184905284919082169063a9059cbb906044016020604051808303816000875af1158015612d72573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122089190613862565b6000612da56002848418613884565b612db19084841661370f565b9392505050565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a08101919091526000600c8481548110612dff57612dff6136f9565b906000526020600020906005020190506000600d8581548110612e2457612e246136f9565b6000918252602090912001905060028154610100900460ff166007811115612e4e57612e4e61354a565b1480612e74575060048154610100900460ff166007811115612e7257612e7261354a565b145b612eb95760405162461bcd60e51b8152602060048201526016602482015275526166666c6520696e2077726f6e672073746174757360501b60448201526064016109d5565b60048201849055612eca85856115c6565b6002830180546001600160a01b0319166001600160a01b0392909216919091179055805461ff00191661050017808255600183015460009161271091612f2a9165ffffffffffff90911690600160701b90046001600160801b0316613898565b612f3491906138bb565b82546001600160801b039182169250600091612f5a918491600160701b909104166136e6565b60038501546040519192506000916001600160a01b039091169083908381818185875af1925050503d8060008114612fae576040519150601f19603f3d011682016040523d82523d6000602084013e612fb3565b606091505b5050905080612ffb5760405162461bcd60e51b81526020600482015260146024820152732330b4b632b2103a379039b2b7321022ba3432b960611b60448201526064016109d5565b600a546040516000916001600160a01b03169085908381818185875af1925050503d8060008114613048576040519150601f19603f3d011682016040523d82523d6000602084013e61304d565b606091505b50509050806130965760405162461bcd60e51b81526020600482015260156024820152744661696c65642073656e642045746820746f204d5760581b60448201526064016109d5565b887f7378e11c2b0ec7514bbf7ba369980eedcba0bca03e116dc9e7138f7748e211d6856040516130c891815260200190565b60405180910390a26002860154855460408051600160701b9092046001600160801b03168252602082018b90526001600160a01b03909216918b917fe0b2a72a0644b093aac275024c05c7c28851a0b572557a32241d13634a0f3e08910160405180910390a350506040805160c08101825285548152600186015465ffffffffffff81166020830152600160301b90046001600160a01b03908116928201929092526002860154821660608201526003860154909116608082015260049094015460a0850152509195945050505050565b600080604083850312156131ac57600080fd5b50508035926020909101359150565b6000602082840312156131cd57600080fd5b81356001600160e01b031981168114612db157600080fd5b6000602082840312156131f757600080fd5b5035919050565b80356001600160801b038116811461321557600080fd5b919050565b803565ffffffffffff8116811461321557600080fd5b80356003811061321557600080fd5b600080600080600080600060c0888a03121561325a57600080fd5b613263886131fe565b965060208801359550613278604089016131fe565b9450606088013567ffffffffffffffff8082111561329557600080fd5b818a0191508a601f8301126132a957600080fd5b8135818111156132b857600080fd5b8b60206060830285010111156132cd57600080fd5b6020830196508095505050506132e56080890161321a565b91506132f360a08901613230565b905092959891949750929550565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561334057613340613301565b604052919050565b600067ffffffffffffffff82111561336257613362613301565b5060051b60200190565b6000806040838503121561337f57600080fd5b8235915060208084013567ffffffffffffffff81111561339e57600080fd5b8401601f810186136133af57600080fd5b80356133c26133bd82613348565b613317565b81815260059190911b820183019083810190888311156133e157600080fd5b928401925b828410156133ff578335825292840192908401906133e6565b80955050505050509250929050565b6001600160a01b038116811461175757600080fd5b6000806040838503121561343657600080fd5b8235915060208301356134488161340e565b809150509250929050565b602080825282518282018190526000919060409081850190868401855b828110156134a6578151805165ffffffffffff1685528601516001600160a01b0316868501529284019290850190600101613470565b5091979650505050505050565b600080604083850312156134c657600080fd5b8235915060208084013567ffffffffffffffff8111156134e557600080fd5b8401601f810186136134f657600080fd5b80356135046133bd82613348565b81815260059190911b8201830190838101908883111561352357600080fd5b928401925b828410156133ff57833561353b8161340e565b82529284019290840190613528565b634e487b7160e01b600052602160045260246000fd5b6008811061357e57634e487b7160e01b600052602160045260246000fd5b9052565b851515815260a081016135986020830187613560565b65ffffffffffff94851660408301529290931660608401526001600160801b031660809092019190915292915050565b6000602082840312156135da57600080fd5b8135612db18161340e565b81511515815260208083015160a083019161360290840182613560565b50604083015165ffffffffffff808216604085015280606086015116606085015250506001600160801b03608084015116608083015292915050565b6000806000806060858703121561365457600080fd5b84359350602085013567ffffffffffffffff8082111561367357600080fd5b818701915087601f83011261368757600080fd5b81358181111561369657600080fd5b8860208260051b85010111156136ab57600080fd5b60208301955080945050505060408501356136c58161340e565b939692955090935050565b634e487b7160e01b600052601160045260246000fd5b818103818111156108f3576108f36136d0565b634e487b7160e01b600052603260045260246000fd5b808201808211156108f3576108f36136d0565b65ffffffffffff818116838216019080821115613741576137416136d0565b5092915050565b606080825284519082018190526000906020906080840190828801845b8281101561378a5781516001600160a01b031684529284019290840190600101613765565b5050506020840195909552505065ffffffffffff91909116604090910152919050565b602081016108f38284613560565b6000602082840312156137cd57600080fd5b5051919050565b6000602082840312156137e657600080fd5b612db18261321a565b60006020828403121561380157600080fd5b81356001600160a81b0381168114612db157600080fd5b634e487b7160e01b600052601260045260246000fd5b60008261383d5761383d613818565b500690565b6001600160801b03818116838216019080821115613741576137416136d0565b60006020828403121561387457600080fd5b81518015158114612db157600080fd5b60008261389357613893613818565b500490565b6001600160801b03818116838216028082169190828114611745576117456136d0565b60006001600160801b03808416806138d5576138d5613818565b9216919091049291505056fe523a704056dcd17bcf83bed8b68c59416dac1119be77755efe3bde0a64e46e0ca2646970667358221220adcdc9fb2cabcba35d43f9c644d5bf0af69bbc9282e5891a21a99a2e4002ff4f64736f6c63430008170033523a704056dcd17bcf83bed8b68c59416dac1119be77755efe3bde0a64e46e0c0000000000000000000000008103b0a8a00be2ddc778e6e7eaa21791cd364625474e34a077df58807dbe9c96d3c009b23b3c6d0cce433e59bbf5b34f823bc56c0000000000000000000000000000000000000000000000000000000000001fb00000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000007a1200000000000000000000000000000000000000000000000000000000000000005
Deployed Bytecode
0x6080604052600436106102045760003560e01c806353b7a59b1161011857806393a75d02116100a0578063d649214c1161006f578063d649214c1461074d578063ddba6e6b1461076d578063f3691455146107ec578063f5b541a61461080c578063f720e7081461082e57600080fd5b806393a75d02146106b7578063a217fddf146106e4578063cf7874a3146106f9578063d547741f1461072d57600080fd5b80637c903fc0116100e75780637c903fc0146105ca5780637fa4cacb146105fe57806381d12c581461061e5780638499e1b21461066757806391d148541461069757600080fd5b806353b7a59b146105145780635d4bc0ce146105345780635fba3171146105975780636ecc20da146105b757600080fd5b8063248a9ca31161019b578063365e36581161016a578063365e36581461044657806336734e341461047357806336a418bf146104935780633a3956c2146104c35780634006efe0146104f457600080fd5b8063248a9ca3146103b65780632f2ff15d146103e6578063317f30591461040657806336568abe1461042657600080fd5b806316e17bf1116101d757806316e17bf1146103075780631a0187f5146103355780631fe543e31461038357806323685496146103a357600080fd5b8063013805c51461020957806301ffc9a714610254578063039be558146102845780630df71602146102e5575b600080fd5b34801561021557600080fd5b50610229610224366004613199565b61087a565b6040805165ffffffffffff90931683526001600160a01b039091166020830152015b60405180910390f35b34801561026057600080fd5b5061027461026f3660046131bb565b6108c2565b604051901515815260200161024b565b34801561029057600080fd5b506102c561029f3660046131e5565b6004602052600090815260409020546001600160801b0380821691600160801b90041682565b604080516001600160801b0393841681529290911660208301520161024b565b3480156102f157600080fd5b506103056103003660046131e5565b6108f9565b005b34801561031357600080fd5b5061032761032236600461323f565b61096e565b60405190815260200161024b565b34801561034157600080fd5b5061036b6103503660046131e5565b6006602052600090815260409020546001600160a01b031681565b6040516001600160a01b03909116815260200161024b565b34801561038f57600080fd5b5061030561039e36600461336c565b610a17565b6103056103b1366004613199565b610a9f565b3480156103c257600080fd5b506103276103d13660046131e5565b60009081526020819052604090206001015490565b3480156103f257600080fd5b50610305610401366004613423565b610abd565b34801561041257600080fd5b506103056104213660046131e5565b610ae2565b34801561043257600080fd5b50610305610441366004613423565b610caf565b34801561045257600080fd5b506104666104613660046131e5565b610ce2565b60405161024b9190613453565b34801561047f57600080fd5b5061030561048e3660046134b3565b610d70565b34801561049f57600080fd5b506102746104ae3660046131e5565b60086020526000908152604090205460ff1681565b3480156104cf57600080fd5b506104e36104de3660046131e5565b610f7f565b60405161024b959493929190613582565b34801561050057600080fd5b5061030561050f3660046131e5565b610fd8565b34801561052057600080fd5b50600a5461036b906001600160a01b031681565b34801561054057600080fd5b5061055461054f3660046131e5565b611104565b6040805196875265ffffffffffff90951660208701526001600160a01b0393841694860194909452908216606085015216608083015260a082015260c00161024b565b3480156105a357600080fd5b506103056105b23660046131e5565b611164565b6103056105c53660046131e5565b611187565b3480156105d657600080fd5b506103277fde5ee446972f4e39ab62c03aa34b2096680a875c3fdb3eb2f947cbb93341c05881565b34801561060a57600080fd5b506103056106193660046135c8565b6112c2565b34801561062a57600080fd5b506106526106393660046131e5565b6001602081905260009182526040909120805491015482565b6040805192835260208301919091520161024b565b34801561067357600080fd5b506102746106823660046131e5565b60096020526000908152604090205460ff1681565b3480156106a357600080fd5b506102746106b2366004613423565b6112f0565b3480156106c357600080fd5b506106d76106d23660046131e5565b611319565b60405161024b91906135e5565b3480156106f057600080fd5b50610327600081565b34801561070557600080fd5b506106526107143660046131e5565b6002602052600090815260409020805460019091015482565b34801561073957600080fd5b50610305610748366004613423565b6113ed565b34801561075957600080fd5b5061030561076836600461363e565b611412565b34801561077957600080fd5b506107be6107883660046131e5565b6003602052600090815260409020805460019091015465ffffffffffff80831692600160301b900416906001600160a81b031683565b6040805165ffffffffffff94851681529390921660208401526001600160a81b03169082015260600161024b565b3480156107f857600080fd5b5061036b610807366004613199565b6115c6565b34801561081857600080fd5b506103276000805160206138e283398151915281565b34801561083a57600080fd5b506108636108493660046131e5565b60076020526000908152604090205465ffffffffffff1681565b60405165ffffffffffff909116815260200161024b565b6005602052816000526040600020818154811061089657600080fd5b60009182526020909120015465ffffffffffff81169250600160301b90046001600160a01b0316905082565b60006001600160e01b03198216637965db0b60e01b14806108f357506301ffc9a760e01b6001600160e01b03198316145b92915050565b6000805160206138e28339815191526109118161174d565b600061091c8361175a565b905060006109286119cb565b905061096884836060015165ffffffffffff1683604080518082018252938452602080850193845260009283526002905290209151825551600190910155565b50505050565b60006000805160206138e28339815191526109888161174d565b6113888465ffffffffffff1611156109de57604051636b221d4560e11b81526020600482015260136024820152720c6dedadad2e6e6d2dedc40e8dede40d0d2ced606b1b60448201526064015b60405180910390fd5b6109ef8960008a8a8a8a8a8a611b28565b6109f7611fd7565b600c54600090610a09906001906136e6565b9a9950505050505050505050565b336001600160a01b037f0000000000000000000000008103b0a8a00be2ddc778e6e7eaa21791cd3646251614610a915760405163073e64fd60e21b81523360048201526001600160a01b037f0000000000000000000000008103b0a8a00be2ddc778e6e7eaa21791cd3646251660248201526044016109d5565b610a9b82826120ee565b5050565b6000610aab838361220f565b9050610ab88184846126bb565b505050565b600082815260208190526040902060010154610ad88161174d565b610968838361280a565b6000805160206138e2833981519152610afa8161174d565b6000600d8381548110610b0f57610b0f6136f9565b6000918252602090912001905060068154610100900460ff166007811115610b3957610b3961354a565b1480610b5f575060038154610100900460ff166007811115610b5d57610b5d61354a565b145b610b9a5760405162461bcd60e51b815260206004820152600c60248201526b57726f6e672073746174757360a01b60448201526064016109d5565b805461ff00191661030017808255600a546040516000926001600160a01b0390921691600160701b90046001600160801b0316908381818185875af1925050503d8060008114610c06576040519150601f19603f3d011682016040523d82523d6000602084013e610c0b565b606091505b5050905080610c525760405162461bcd60e51b81526020600482015260136024820152724661696c2073656e642045746820746f204d5760681b60448201526064016109d5565b8154604051600160701b9091046001600160801b0316815284907fcdef6558dae40f2699846eedf449462daab85b1224ad7f077569ba91aaa949259060200160405180910390a2508054600160701b600160f01b03191690555050565b6001600160a01b0381163314610cd85760405163334bd91960e11b815260040160405180910390fd5b610ab8828261289c565b606060056000838152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015610d65576000848152602090819020604080518082019091529084015465ffffffffffff81168252600160301b90046001600160a01b031681830152825260019092019101610d17565b505050509050919050565b6000805160206138e2833981519152610d888161174d565b6000600d8481548110610d9d57610d9d6136f9565b6000918252602090912001905060018154610100900460ff166007811115610dc757610dc761354a565b14610e145760405162461bcd60e51b815260206004820152601960248201527f526166666c65206973206e6f7420696e2061636365707465640000000000000060448201526064016109d5565b82516000805b82811015610ef0576000868281518110610e3657610e366136f9565b6020026020010151905060006040518060400160405280848860000160089054906101000a900465ffffffffffff1665ffffffffffff16610e77919061370f565b610e8290600161370f565b65ffffffffffff90811682526001600160a01b0394851660209283015260008c81526005835260408120805460018181018355918352918490208551920180549590940151909616600160301b026001600160d01b0319909416911617919091179055509182019101610e1a565b508254610f0d908290600160401b900465ffffffffffff16613722565b835465ffffffffffff60401b1916600160401b65ffffffffffff92831681029190911780865560405189937f4da4f5fab0816c65315b6f5d15f879f96b98661133d7b3787788f291367604fb93610f6f938b9389939290910490911690613748565b60405180910390a2505050505050565b600d8181548110610f8f57600080fd5b60009182526020909120015460ff80821692506101008204169065ffffffffffff620100008204811691600160401b8104909116906001600160801b03600160701b9091041685565b6000805160206138e2833981519152610ff08161174d565b6004600d8381548110611005576110056136f9565b600091825260209091200154610100900460ff16600781111561102a5761102a61354a565b146110865760405162461bcd60e51b815260206004820152602660248201527f526166666c65206973206e6f7420696e20636c6f73652072657175657374656460448201526520737461746560d01b60648201526084016109d5565b6001600d838154811061109b5761109b6136f9565b6000918252602090912001805461ff0019166101008360078111156110c2576110c261354a565b0217905550817fc1191e7178b58ad510709587719f39ec315fa79e81ee7ba5c5ef3c894e94a65160016040516110f891906137ad565b60405180910390a25050565b600c818154811061111457600080fd5b60009182526020909120600590910201805460018201546002830154600384015460049094015492945065ffffffffffff8216936001600160a01b03600160301b90930483169391831692169086565b6000805160206138e283398151915261117c8161174d565b610a9b826001612907565b6000600d828154811061119c5761119c6136f9565b9060005260206000200190506000600c83815481106111bd576111bd6136f9565b60009182526020822060059091020191508254610100900460ff1660078111156111e9576111e961354a565b1461122b5760405162461bcd60e51b8152602060048201526012602482015271149859999b19481b9bdd0810d4915055115160721b60448201526064016109d5565b8054341461126e5760405162461bcd60e51b815260206004820152601060248201526f141c9a5e99481b9bdd081cdd185ad95960821b60448201526064016109d5565b815461ff0019166101001782556003810180546001600160a01b0319163390811790915560405184907f8bb509eedfd1c4847b0a8a2b4493cf2ebb9970dc367e477cd2a8523e212dc1db90600090a3505050565b60006112cd8161174d565b50600a80546001600160a01b0319166001600160a01b0392909216919091179055565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b6040805160a081018252600080825260208201819052918101829052606081018290526080810191909152600d8281548110611357576113576136f9565b60009182526020918290206040805160a081019091529101805460ff80821615158452929391929184019161010090910416600781111561139a5761139a61354a565b60078111156113ab576113ab61354a565b8152905465ffffffffffff62010000820481166020840152600160401b82041660408301526001600160801b03600160701b9091041660609091015292915050565b6000828152602081905260409020600101546114088161174d565b610968838361289c565b6000805160206138e283398151915261142a8161174d565b6000805b84811015611585576000878152600560205260408120878784818110611456576114566136f9565b9050602002013560010181548110611470576114706136f9565b600091825260209091200180549091506001600160a01b03868116600160301b90920416146114e15760405162461bcd60e51b815260206004820152601e60248201527f456e74727920646964206e6f742062656c6f6e6720746f20706c61796572000060448201526064016109d5565b80546601000000000000600160d01b03191681556000878784818110611509576115096136f9565b9050602002013560000361151f5750600061156d565b600089815260056020526040902088888581811061153f5761153f6136f9565b9050602002013581548110611556576115566136f9565b60009182526020909120015465ffffffffffff1690505b905465ffffffffffff1603919091019060010161142e565b50604080518281526001600160a01b038516602082015287917f2cca80c1af5abb202a642a502875436822768d733462843a7c3a902b0fad99d09101610f6f565b600082815260056020526040812081906115e09084612ae5565b60008581526005602052604081208054929350909183908110611605576116056136f9565b600091825260209091200154600160301b90046001600160a01b0316905080156116325791506108f39050565b6000825b8115801561167d5750600087815260056020526040812080548390811061165f5761165f6136f9565b600091825260209091200154600160301b90046001600160a01b0316145b156116b757806000036116ac576000878152600560205260409020546116a5906001906136e6565b9050611636565b6116a56001826136e6565b81156116fd5760405162461bcd60e51b8152602060048201526015602482015274105b1b081d5cd95c9cc8189b1858dadb1a5cdd1959605a1b60448201526064016109d5565b600087815260056020526040902080548290811061171d5761171d6136f9565b600091825260209091200154600160301b90046001600160a01b031694506108f39350505050565b505092915050565b6117578133612bbc565b50565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091526000600d838154811061179a5761179a6136f9565b60009182526020808320868452600490915260409092209101915060018254610100900460ff1660078111156117d2576117d261354a565b146118185760405162461bcd60e51b8152602060048201526016602482015275526166666c6520696e2077726f6e672073746174757360501b60448201526064016109d5565b805482546001600160801b03918216600160701b90910490911610156118805760405162461bcd60e51b815260206004820152601760248201527f4e6f7420656e6f7567682066756e64732072616973656400000000000000000060448201526064016109d5565b81548154600160701b9091046001600160801b03908116600160801b9092041611156118ee5760405162461bcd60e51b815260206004820152601860248201527f446573697265642066756e6473206e6f7420726169736564000000000000000060448201526064016109d5565b815461ff0019166104001780835560408051600160701b9092046001600160801b031682525185917ff2be214756d2fbc1e781d10809ddef33000009d805be55356bb348134ce21c68919081900360200190a26040805160a08101909152825460ff80821615158352849160208401916101009091041660078111156119765761197661354a565b60078111156119875761198761354a565b8152905465ffffffffffff62010000820481166020840152600160401b82041660408301526001600160801b03600160701b90910416606090910152949350505050565b6040516305d3b1d360e41b81527f474e34a077df58807dbe9c96d3c009b23b3c6d0cce433e59bbf5b34f823bc56c600482015267ffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000001fb016602482015261ffff7f000000000000000000000000000000000000000000000000000000000000000316604482015263ffffffff7f000000000000000000000000000000000000000000000000000000000007a120811660648301527f000000000000000000000000000000000000000000000000000000000000000516608482015260009081906001600160a01b037f0000000000000000000000008103b0a8a00be2ddc778e6e7eaa21791cd3646251690635d3b1d309060a4016020604051808303816000875af1158015611b04573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108f391906137bb565b6040805160c08101825287815265ffffffffffff808516602083019081526001600160a01b03808c169484019485526000606085018181526080860182815260a08701838152600c8054600181810183558287528a5160059092027fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c781019290925597517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c8820180549c518916600160301b026001600160d01b0319909d1691909a16179a909a1790975591517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c9890180549186166001600160a01b031992831617905590517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8ca890180549190951691161790925590517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8cb909501949094559054919291611c9691906136e6565b90506000859003611cd657604051636b221d4560e11b81526020600482015260096024820152684e6f2070726963657360b81b60448201526064016109d5565b60005b85811015611e8957868682818110611cf357611cf36136f9565b9050606002016020016020810190611d0b91906137d4565b65ffffffffffff16600003611d5557604051636b221d4560e11b815260206004820152600f60248201526e06e756d456e7472696573206973203608c1b60448201526064016109d5565b600060405180606001604052808465ffffffffffff168152602001898985818110611d8257611d826136f9565b9050606002016020016020810190611d9a91906137d4565b65ffffffffffff168152602001898985818110611db957611db96136f9565b9050606002016040016020810190611dd191906137ef565b6001600160a81b03169052905080600360008a8a86818110611df557611df56136f9565b611e0b92602060609092020190810191506137d4565b65ffffffffffff9081168252602080830193909352604091820160002084518154948601518316600160301b026bffffffffffffffffffffffff199095169216919091179290921782559190910151600191820180546001600160a81b039092166001600160a81b0319909216919091179055919091019050611cd9565b50604080518082019091526001600160801b0380891682528b166020820152600c54600490600090611ebd906001906136e6565b8152602080820192909252604001600020825192909101516001600160801b03908116600160801b029216919091179055600c5488906001600160a01b038b1690611f0a906001906136e6565b6040517f81781e053ec72aa8731479536c4da8f819ef3283d2c0dea5c4f0d938bed8489590600090a460408051808201825260018082523360208084019182526000868152600582529485208054938401815580865290852084519301805492516001600160a01b0316600160301b026001600160d01b031990931665ffffffffffff949094169390931791909117909155838352805491929091611fb157611fb16136f9565b600091825260209091200180546001600160d01b03191690555050505050505050505050565b6040805160a0810182526000808252602082018181529282018190526060820181905260808201819052600d8054600181018255915281517fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb5909101805491151560ff198316811782559351929384939192839161ff00191661ffff199091161761010083600781111561206d5761206d61354a565b02179055506040820151815460608401516080909401516dffffffffffffffffffffffff0000199091166201000065ffffffffffff9384160265ffffffffffff60401b191617600160401b929094169190910292909217600160701b600160f01b031916600160701b6001600160801b039093169290920291909117905550565b6000828152600260209081526040808320815180830190925280548252600101549181018290528351909291908490839061212b5761212b6136f9565b602002602001015161213d919061382e565b61214890600161370f565b9050600060405180604001604052808560008151811061216a5761216a6136f9565b602090810291909101810151825290810184905284516000908152600180835260408220845181559284015192019190915584518651929350917f7c40e661b8212d0c4f60ac6e6ebed99c28680c7b3ede5b82f3b0254543f62fca9187916121d4576121d46136f9565b6020026020010151846040516121f4929190918252602082015260400190565b60405180910390a282516122089083612bf5565b5050505050565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091523233146122815760405163efeb42cf60e01b8152602060048201526014602482015273139bc818dbdb9d1c9858dd1cc8185b1b1bddd95960621b60448201526064016109d5565b6000600d8481548110612296576122966136f9565b6000918252602090912001905060018154610100900460ff1660078111156122c0576122c061354a565b146123005760405163efeb42cf60e01b815260206004820152600f60248201526e139bdd081a5b881050d0d154151151608a1b60448201526064016109d5565b6000838152600360209081526040918290208251606081018452815465ffffffffffff808216808452600160301b90920416938201939093526001909101546001600160a81b03169281019290925285146123935760405163efeb42cf60e01b81526020600482015260126024820152711259081b9bdd081a5b881c9859999b19525960721b60448201526064016109d5565b602081015160408201516001600160a81b031634146123f55760405163efeb42cf60e01b815260206004820152601760248201527f6d73672e76616c7565206e6f742074686520707269636500000000000000000060448201526064016109d5565b81604001516001600160a81b03166000036124b7576040805133602082015290810187905260009060600160408051601f1981840301815291815281516020928301206000818152600990935291205490915060ff16151560010361249d5760405163efeb42cf60e01b815260206004820152601d60248201527f506c6179657220616c726561647920676f74206672656520656e74727900000060448201526064016109d5565b6000908152600960205260409020805460ff191660011790555b825460408051808201909152600160401b90910465ffffffffffff1690600090806124e28585613722565b65ffffffffffff90811682523360209283015260008b815260058352604081208054600181018255818352848320865191018054958701516001600160a01b0316600160301b026001600160d01b03199096169190941617939093179091558a815281549293509091612557576125576136f9565b600091825260209091200180546001600160d01b0319169055845434908690600e90612594908490600160701b90046001600160801b0316613842565b92506101000a8154816001600160801b0302191690836001600160801b0316021790555082826125c49190613722565b855465ffffffffffff60401b1916600160401b65ffffffffffff928316810291909117808855604080519290910490921681526020810189905233918a917fd746af8dc82f9bed98cea0fe0264eb1c3d2e5f7bcc77fc5efb429c79df407887910160405180910390a36040805160a08101909152855460ff80821615158352879160208401916101009091041660078111156126625761266261354a565b60078111156126735761267361354a565b8152905462010000810465ffffffffffff9081166020840152600160401b8204166040830152600160701b90046001600160801b031660609091015298975050505050505050565b604083015165ffffffffffff1615610ab8576000818152600360209081526040808320815160608082018452825465ffffffffffff8082168452600160301b90910481168387019081526001909401546001600160a81b03168386015284518087018a90523381870152855180820387018152920185528151918601919091208087526007909552948390205492880151915190949283169291909116906127639083613722565b65ffffffffffff1611156127b05760405163efeb42cf60e01b815260206004820152601360248201527215d85b1b195d08185b1c9958591e481d5cd959606a1b60448201526064016109d5565b602080840151600084815260079092526040909120546127d8919065ffffffffffff16613722565b600092835260076020526040909220805465ffffffffffff191665ffffffffffff909316929092179091555050505050565b600061281683836112f0565b612894576000838152602081815260408083206001600160a01b03861684529091529020805460ff1916600117905561284c3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016108f3565b5060006108f3565b60006128a883836112f0565b15612894576000838152602081815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45060016108f3565b6000600c838154811061291c5761291c6136f9565b906000526020600020906005020190506000600d8481548110612941576129416136f9565b6000918252602090912001905060018154610100900460ff16600781111561296b5761296b61354a565b1480612991575060008154610100900460ff16600781111561298f5761298f61354a565b145b6129cc5760405162461bcd60e51b815260206004820152600c60248201526b57726f6e672073746174757360a01b60448201526064016109d5565b60018154610100900460ff1660078111156129e9576129e961354a565b03612a8c578265ffffffffffff16600003612a2857600182015482546003840154612a28926001600160a01b03600160301b9091048116929116612c15565b8265ffffffffffff16600103612a525781546003830154612a5291906001600160a01b0316612c86565b8265ffffffffffff16600203612a8c57600182015482546003840154612a8c926001600160a01b03600160301b9091048116929116612d20565b805461ff0019166106001780825560408051600160701b9092046001600160801b031682525185917fd512a34b0f0618078770fcd85d974df1ab46a7882e8b3d45aa91764f4961aed2919081900360200190a250505050565b81546000908103612af8575060006108f3565b82546000905b80821015612b5d576000612b128383612d96565b905084868281548110612b2757612b276136f9565b60009182526020909120015465ffffffffffff161115612b4957809150612b57565b612b5481600161370f565b92505b50612afe565b600082118015612b9b57508385612b756001856136e6565b81548110612b8557612b856136f9565b60009182526020909120015465ffffffffffff16145b15612bb457612bab6001836136e6565b925050506108f3565b5090506108f3565b612bc682826112f0565b610a9b5760405163e2517d3f60e01b81526001600160a01b0382166004820152602481018390526044016109d5565b6000612c018383612db8565b9050610ab881600001518260600151612c86565b6040516323b872dd60e01b81523060048201526001600160a01b038281166024830152604482018490528491908216906323b872dd90606401600060405180830381600087803b158015612c6857600080fd5b505af1158015612c7c573d6000803e3d6000fd5b5050505050505050565b6000816001600160a01b03168360405160006040518083038185875af1925050503d8060008114612cd3576040519150601f19603f3d011682016040523d82523d6000602084013e612cd8565b606091505b5050905080610ab85760405162461bcd60e51b81526020600482015260146024820152732330b4b632b2103a379039b2b7321022ba3432b960611b60448201526064016109d5565b60405163a9059cbb60e01b81526001600160a01b0382811660048301526024820184905284919082169063a9059cbb906044016020604051808303816000875af1158015612d72573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122089190613862565b6000612da56002848418613884565b612db19084841661370f565b9392505050565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a08101919091526000600c8481548110612dff57612dff6136f9565b906000526020600020906005020190506000600d8581548110612e2457612e246136f9565b6000918252602090912001905060028154610100900460ff166007811115612e4e57612e4e61354a565b1480612e74575060048154610100900460ff166007811115612e7257612e7261354a565b145b612eb95760405162461bcd60e51b8152602060048201526016602482015275526166666c6520696e2077726f6e672073746174757360501b60448201526064016109d5565b60048201849055612eca85856115c6565b6002830180546001600160a01b0319166001600160a01b0392909216919091179055805461ff00191661050017808255600183015460009161271091612f2a9165ffffffffffff90911690600160701b90046001600160801b0316613898565b612f3491906138bb565b82546001600160801b039182169250600091612f5a918491600160701b909104166136e6565b60038501546040519192506000916001600160a01b039091169083908381818185875af1925050503d8060008114612fae576040519150601f19603f3d011682016040523d82523d6000602084013e612fb3565b606091505b5050905080612ffb5760405162461bcd60e51b81526020600482015260146024820152732330b4b632b2103a379039b2b7321022ba3432b960611b60448201526064016109d5565b600a546040516000916001600160a01b03169085908381818185875af1925050503d8060008114613048576040519150601f19603f3d011682016040523d82523d6000602084013e61304d565b606091505b50509050806130965760405162461bcd60e51b81526020600482015260156024820152744661696c65642073656e642045746820746f204d5760581b60448201526064016109d5565b887f7378e11c2b0ec7514bbf7ba369980eedcba0bca03e116dc9e7138f7748e211d6856040516130c891815260200190565b60405180910390a26002860154855460408051600160701b9092046001600160801b03168252602082018b90526001600160a01b03909216918b917fe0b2a72a0644b093aac275024c05c7c28851a0b572557a32241d13634a0f3e08910160405180910390a350506040805160c08101825285548152600186015465ffffffffffff81166020830152600160301b90046001600160a01b03908116928201929092526002860154821660608201526003860154909116608082015260049094015460a0850152509195945050505050565b600080604083850312156131ac57600080fd5b50508035926020909101359150565b6000602082840312156131cd57600080fd5b81356001600160e01b031981168114612db157600080fd5b6000602082840312156131f757600080fd5b5035919050565b80356001600160801b038116811461321557600080fd5b919050565b803565ffffffffffff8116811461321557600080fd5b80356003811061321557600080fd5b600080600080600080600060c0888a03121561325a57600080fd5b613263886131fe565b965060208801359550613278604089016131fe565b9450606088013567ffffffffffffffff8082111561329557600080fd5b818a0191508a601f8301126132a957600080fd5b8135818111156132b857600080fd5b8b60206060830285010111156132cd57600080fd5b6020830196508095505050506132e56080890161321a565b91506132f360a08901613230565b905092959891949750929550565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561334057613340613301565b604052919050565b600067ffffffffffffffff82111561336257613362613301565b5060051b60200190565b6000806040838503121561337f57600080fd5b8235915060208084013567ffffffffffffffff81111561339e57600080fd5b8401601f810186136133af57600080fd5b80356133c26133bd82613348565b613317565b81815260059190911b820183019083810190888311156133e157600080fd5b928401925b828410156133ff578335825292840192908401906133e6565b80955050505050509250929050565b6001600160a01b038116811461175757600080fd5b6000806040838503121561343657600080fd5b8235915060208301356134488161340e565b809150509250929050565b602080825282518282018190526000919060409081850190868401855b828110156134a6578151805165ffffffffffff1685528601516001600160a01b0316868501529284019290850190600101613470565b5091979650505050505050565b600080604083850312156134c657600080fd5b8235915060208084013567ffffffffffffffff8111156134e557600080fd5b8401601f810186136134f657600080fd5b80356135046133bd82613348565b81815260059190911b8201830190838101908883111561352357600080fd5b928401925b828410156133ff57833561353b8161340e565b82529284019290840190613528565b634e487b7160e01b600052602160045260246000fd5b6008811061357e57634e487b7160e01b600052602160045260246000fd5b9052565b851515815260a081016135986020830187613560565b65ffffffffffff94851660408301529290931660608401526001600160801b031660809092019190915292915050565b6000602082840312156135da57600080fd5b8135612db18161340e565b81511515815260208083015160a083019161360290840182613560565b50604083015165ffffffffffff808216604085015280606086015116606085015250506001600160801b03608084015116608083015292915050565b6000806000806060858703121561365457600080fd5b84359350602085013567ffffffffffffffff8082111561367357600080fd5b818701915087601f83011261368757600080fd5b81358181111561369657600080fd5b8860208260051b85010111156136ab57600080fd5b60208301955080945050505060408501356136c58161340e565b939692955090935050565b634e487b7160e01b600052601160045260246000fd5b818103818111156108f3576108f36136d0565b634e487b7160e01b600052603260045260246000fd5b808201808211156108f3576108f36136d0565b65ffffffffffff818116838216019080821115613741576137416136d0565b5092915050565b606080825284519082018190526000906020906080840190828801845b8281101561378a5781516001600160a01b031684529284019290840190600101613765565b5050506020840195909552505065ffffffffffff91909116604090910152919050565b602081016108f38284613560565b6000602082840312156137cd57600080fd5b5051919050565b6000602082840312156137e657600080fd5b612db18261321a565b60006020828403121561380157600080fd5b81356001600160a81b0381168114612db157600080fd5b634e487b7160e01b600052601260045260246000fd5b60008261383d5761383d613818565b500690565b6001600160801b03818116838216019080821115613741576137416136d0565b60006020828403121561387457600080fd5b81518015158114612db157600080fd5b60008261389357613893613818565b500490565b6001600160801b03818116838216028082169190828114611745576117456136d0565b60006001600160801b03808416806138d5576138d5613818565b9216919091049291505056fe523a704056dcd17bcf83bed8b68c59416dac1119be77755efe3bde0a64e46e0ca2646970667358221220adcdc9fb2cabcba35d43f9c644d5bf0af69bbc9282e5891a21a99a2e4002ff4f64736f6c63430008170033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000008103b0a8a00be2ddc778e6e7eaa21791cd364625474e34a077df58807dbe9c96d3c009b23b3c6d0cce433e59bbf5b34f823bc56c0000000000000000000000000000000000000000000000000000000000001fb00000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000007a1200000000000000000000000000000000000000000000000000000000000000005
-----Decoded View---------------
Arg [0] : _vrfCoordinator (address): 0x8103B0A8A00be2DDC778e6e7eaa21791Cd364625
Arg [1] : _keyHash (bytes32): 0x474e34a077df58807dbe9c96d3c009b23b3c6d0cce433e59bbf5b34f823bc56c
Arg [2] : _subId (uint64): 8112
Arg [3] : _minimumRequestConfirmations (uint16): 3
Arg [4] : _callbackGasLimit (uint32): 500000
Arg [5] : _numWords (uint32): 5
-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 0000000000000000000000008103b0a8a00be2ddc778e6e7eaa21791cd364625
Arg [1] : 474e34a077df58807dbe9c96d3c009b23b3c6d0cce433e59bbf5b34f823bc56c
Arg [2] : 0000000000000000000000000000000000000000000000000000000000001fb0
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [4] : 000000000000000000000000000000000000000000000000000000000007a120
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000005
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.