Sepolia Testnet

Contract

0xc89306320ADFF25e0a10631DB5FdffB6e9e87830

Overview

ETH Balance

0.0326 ETH

Multichain Info

N/A
Transaction Hash
Method
Block
From
To
Buy Entry74051162025-01-02 9:17:3648 days ago1735809456IN
0xc8930632...6e9e87830
0.005 ETH0.0029033643.11314698
Stake ETH74051052025-01-02 9:15:2448 days ago1735809324IN
0xc8930632...6e9e87830
0.001 ETH0.0037346450.46958442
Create Raffle74051032025-01-02 9:15:0048 days ago1735809300IN
0xc8930632...6e9e87830
0 ETH0.0123861752.01192699
Buy Entry73867112024-12-30 16:04:4850 days ago1735574688IN
0xc8930632...6e9e87830
0.005 ETH0.000484187.18981002
Stake ETH73867082024-12-30 16:04:0050 days ago1735574640IN
0xc8930632...6e9e87830
0.001 ETH0.000530517.16936251
Create Raffle73867062024-12-30 16:03:3650 days ago1735574616IN
0xc8930632...6e9e87830
0 ETH0.002943816.28942547
Buy Entry73862752024-12-30 14:32:1250 days ago1735569132IN
0xc8930632...6e9e87830
0.001 ETH0.000567328.42442201
Buy Entry73862632024-12-30 14:29:2450 days ago1735568964IN
0xc8930632...6e9e87830
0.001 ETH0.000499057.41071066
Stake ETH73862602024-12-30 14:28:4850 days ago1735568928IN
0xc8930632...6e9e87830
0.001 ETH0.000554567.49432117
Create Raffle73862582024-12-30 14:28:2450 days ago1735568904IN
0xc8930632...6e9e87830
0 ETH0.001481016.21906565
Cancel Raffle65379762024-08-20 17:06:24182 days ago1724173584IN
0xc8930632...6e9e87830
0 ETH0.000090221.84117084
Buy Entry65379732024-08-20 17:05:48182 days ago1724173548IN
0xc8930632...6e9e87830
0.001 ETH0.00018942.81258741
Stake ETH65379662024-08-20 17:04:12182 days ago1724173452IN
0xc8930632...6e9e87830
0.001 ETH0.000206292.78789232
Create Raffle65379612024-08-20 17:03:00182 days ago1724173380IN
0xc8930632...6e9e87830
0 ETH0.000835451.78493148
Cancel Raffle65379262024-08-20 16:55:12182 days ago1724172912IN
0xc8930632...6e9e87830
0 ETH0.000081941.67222875
Buy Entry65379222024-08-20 16:54:24182 days ago1724172864IN
0xc8930632...6e9e87830
0.001 ETH0.000178952.65737256
Stake ETH65379182024-08-20 16:53:00182 days ago1724172780IN
0xc8930632...6e9e87830
0.001 ETH0.000195112.63674817
Create Raffle65379022024-08-20 16:49:12182 days ago1724172552IN
0xc8930632...6e9e87830
0 ETH0.00076261.62930112
Cancel Raffle64097352024-07-31 11:36:36203 days ago1722425796IN
0xc8930632...6e9e87830
0 ETH0.000366387.47685874
Cancel Raffle64097172024-07-31 11:32:24203 days ago1722425544IN
0xc8930632...6e9e87830
0 ETH0.000383637.82882207
Cancel Raffle64096992024-07-31 11:28:36203 days ago1722425316IN
0xc8930632...6e9e87830
0 ETH0.000442928.44119903
Cancel Raffle64096982024-07-31 11:28:12203 days ago1722425292IN
0xc8930632...6e9e87830
0 ETH0.00044258.433116
Buy Entry64028592024-07-30 9:35:36204 days ago1722332136IN
0xc8930632...6e9e87830
0.0001 ETH0.0022551933.48819961
Cancel Raffle63798322024-07-26 15:24:48207 days ago1722007488IN
0xc8930632...6e9e87830
0 ETH0.0015979632.60957895
Give Batch Entri...63783762024-07-26 9:24:24208 days ago1721985864IN
0xc8930632...6e9e87830
0 ETH0.0032592351.32970618
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block
From
To
65379762024-08-20 17:06:24182 days ago1724173584
0xc8930632...6e9e87830
0.001 ETH
65379262024-08-20 16:55:12182 days ago1724172912
0xc8930632...6e9e87830
0.001 ETH
64097352024-07-31 11:36:36203 days ago1722425796
0xc8930632...6e9e87830
0.1 ETH
64097172024-07-31 11:32:24203 days ago1722425544
0xc8930632...6e9e87830
0.001 ETH
63798322024-07-26 15:24:48207 days ago1722007488
0xc8930632...6e9e87830
0.001 ETH
55457022024-03-23 16:21:00332 days ago1711210860
0xc8930632...6e9e87830
0.001 ETH
54770802024-03-13 11:36:00343 days ago1710329760
0xc8930632...6e9e87830
0.001 ETH
54770802024-03-13 11:36:00343 days ago1710329760
0xc8930632...6e9e87830
0.0001 ETH
54769982024-03-13 11:18:00343 days ago1710328680
0xc8930632...6e9e87830
0.001 ETH
54769982024-03-13 11:18:00343 days ago1710328680
0xc8930632...6e9e87830
0.0001 ETH
54769982024-03-13 11:18:00343 days ago1710328680
0xc8930632...6e9e87830
0.001 ETH
54769982024-03-13 11:18:00343 days ago1710328680
0xc8930632...6e9e87830
0.0001 ETH
54769202024-03-13 11:01:36343 days ago1710327696
0xc8930632...6e9e87830
0.1 ETH
54769202024-03-13 11:01:36343 days ago1710327696
0xc8930632...6e9e87830
0.0002 ETH
54769192024-03-13 11:01:24343 days ago1710327684
0xc8930632...6e9e87830
0.001 ETH
54769192024-03-13 11:01:24343 days ago1710327684
0xc8930632...6e9e87830
0.0001 ETH
54769192024-03-13 11:01:24343 days ago1710327684
0xc8930632...6e9e87830
0.001 ETH
54769192024-03-13 11:01:24343 days ago1710327684
0xc8930632...6e9e87830
0.0001 ETH
54668542024-03-12 0:01:00344 days ago1710201660
0xc8930632...6e9e87830
0.001 ETH
54668542024-03-12 0:01:00344 days ago1710201660
0xc8930632...6e9e87830
0.0008 ETH
54228342024-03-05 16:57:12350 days ago1709657832
0xc8930632...6e9e87830
0.0001 ETH
54228342024-03-05 16:57:12350 days ago1709657832
0xc8930632...6e9e87830
0.0001 ETH
54226582024-03-05 16:19:24350 days ago1709655564
0xc8930632...6e9e87830
0.0001 ETH
54226582024-03-05 16:19:24350 days ago1709655564
0xc8930632...6e9e87830
0.0001 ETH
53951182024-03-01 15:22:00354 days ago1709306520
0xc8930632...6e9e87830
0.0001 ETH
View All Internal Transactions
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)

File 1 of 16 : ETHComp.sol
// 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);
    }
   
}

File 2 of 16 : AccessControl.sol
// 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;
        }
    }
}

File 3 of 16 : IAccessControl.sol
// 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;
}

File 4 of 16 : IERC20.sol
// 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);
}

File 5 of 16 : IERC721.sol
// 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);
}

File 6 of 16 : Context.sol
// 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;
    }
}

File 7 of 16 : ERC165.sol
// 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;
    }
}

File 8 of 16 : IERC165.sol
// 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);
}

File 9 of 16 : Math.sol
// 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;
    }
}

File 10 of 16 : IDelegationRegistry.sol
// 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);
}

File 11 of 16 : BaseCompetition.sol
// 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); 
    }
}

File 12 of 16 : Constants.sol
//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);
    }
}

File 13 of 16 : VRFCoordinatorV2Interface.sol
// 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);
}

File 14 of 16 : MinimalBase.sol
// 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;
        }
    }



}

File 15 of 16 : MinimalConstants.sol
//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);

}

File 16 of 16 : VRFConsumerBaseV2.sol
// 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);
  }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "evmVersion": "paris",
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract ABI

[{"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"}]

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


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ 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.