false
true
0

Contract Address Details

0xB3aAd2b83156967070B0a7cade049C9a6Ce10da8

Contract Name
ERC721Marketplace
Creator
0x51034d–782d8b at 0x5c2614–bd2b66
Balance
364,197,454.8522403888320002 PLS ( )
Tokens
Fetching tokens...
Transactions
31,623 Transactions
Transfers
0 Transfers
Gas Used
0
Last Balance Update
26131517
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
ERC721Marketplace




Optimization enabled
true
Compiler version
v0.8.17+commit.8df45f5f




Optimization runs
20000
EVM Version
default




Verified at
2023-10-20T00:11:50.281114Z

Constructor Arguments

0x000000000000000000000000476559a5665f8f42402e42b04b0a4cfd6769b7b8000000000000000000000000d032365c138e7385bc50f6df12fe5ef8eca8f0ec000000000000000000000000207e6b4529840a4fd518f73c68bc9c19b2a15944

Arg [0] (address) : 0x476559a5665f8f42402e42b04b0a4cfd6769b7b8
Arg [1] (address) : 0xd032365c138e7385bc50f6df12fe5ef8eca8f0ec
Arg [2] (address) : 0x207e6b4529840a4fd518f73c68bc9c19b2a15944

              

Contract source code

// File: @openzeppelin/contracts/utils/Context.sol


// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

// File: @openzeppelin/contracts/access/Ownable.sol


// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)

pragma solidity ^0.8.0;


/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

// File: @openzeppelin/contracts/security/ReentrancyGuard.sol


// OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be _NOT_ENTERED
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}

// File: @openzeppelin/contracts/utils/Address.sol


// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

// File: @openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol


// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

// File: @openzeppelin/contracts/token/ERC20/IERC20.sol


// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @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 amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` 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 amount) 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 `amount` 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 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` 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 amount
    ) external returns (bool);
}

// File: @openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol


// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;




/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    function safeTransfer(
        IERC20 token,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(
        IERC20 token,
        address from,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 newAllowance = token.allowance(address(this), spender) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            uint256 newAllowance = oldAllowance - value;
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    }

    function safePermit(
        IERC20Permit token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) {
            // Return data is optional
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

// File: @openzeppelin/contracts/utils/introspection/IERC165.sol


// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

// File: @openzeppelin/contracts/utils/introspection/ERC165.sol


// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.0;


/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

// File: @openzeppelin/contracts/interfaces/IERC2981.sol


// OpenZeppelin Contracts (last updated v4.6.0) (interfaces/IERC2981.sol)

pragma solidity ^0.8.0;


/**
 * @dev Interface for the NFT Royalty Standard.
 *
 * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal
 * support for royalty payments across all NFT marketplaces and ecosystem participants.
 *
 * _Available since v4.5._
 */
interface IERC2981 is IERC165 {
    /**
     * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of
     * exchange. The royalty amount is denominated and should be paid in that same unit of exchange.
     */
    function royaltyInfo(uint256 tokenId, uint256 salePrice)
        external
        view
        returns (address receiver, uint256 royaltyAmount);
}

// File: @openzeppelin/contracts/token/common/ERC2981.sol


// OpenZeppelin Contracts (last updated v4.7.0) (token/common/ERC2981.sol)

pragma solidity ^0.8.0;



/**
 * @dev Implementation of the NFT Royalty Standard, a standardized way to retrieve royalty payment information.
 *
 * Royalty information can be specified globally for all token ids via {_setDefaultRoyalty}, and/or individually for
 * specific token ids via {_setTokenRoyalty}. The latter takes precedence over the first.
 *
 * Royalty is specified as a fraction of sale price. {_feeDenominator} is overridable but defaults to 10000, meaning the
 * fee is specified in basis points by default.
 *
 * IMPORTANT: ERC-2981 only specifies a way to signal royalty information and does not enforce its payment. See
 * https://eips.ethereum.org/EIPS/eip-2981#optional-royalty-payments[Rationale] in the EIP. Marketplaces are expected to
 * voluntarily pay royalties together with sales, but note that this standard is not yet widely supported.
 *
 * _Available since v4.5._
 */
abstract contract ERC2981 is IERC2981, ERC165 {
    struct RoyaltyInfo {
        address receiver;
        uint96 royaltyFraction;
    }

    RoyaltyInfo private _defaultRoyaltyInfo;
    mapping(uint256 => RoyaltyInfo) private _tokenRoyaltyInfo;

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) {
        return interfaceId == type(IERC2981).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @inheritdoc IERC2981
     */
    function royaltyInfo(uint256 _tokenId, uint256 _salePrice) public view virtual override returns (address, uint256) {
        RoyaltyInfo memory royalty = _tokenRoyaltyInfo[_tokenId];

        if (royalty.receiver == address(0)) {
            royalty = _defaultRoyaltyInfo;
        }

        uint256 royaltyAmount = (_salePrice * royalty.royaltyFraction) / _feeDenominator();

        return (royalty.receiver, royaltyAmount);
    }

    /**
     * @dev The denominator with which to interpret the fee set in {_setTokenRoyalty} and {_setDefaultRoyalty} as a
     * fraction of the sale price. Defaults to 10000 so fees are expressed in basis points, but may be customized by an
     * override.
     */
    function _feeDenominator() internal pure virtual returns (uint96) {
        return 10000;
    }

    /**
     * @dev Sets the royalty information that all ids in this contract will default to.
     *
     * Requirements:
     *
     * - `receiver` cannot be the zero address.
     * - `feeNumerator` cannot be greater than the fee denominator.
     */
    function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual {
        require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice");
        require(receiver != address(0), "ERC2981: invalid receiver");

        _defaultRoyaltyInfo = RoyaltyInfo(receiver, feeNumerator);
    }

    /**
     * @dev Removes default royalty information.
     */
    function _deleteDefaultRoyalty() internal virtual {
        delete _defaultRoyaltyInfo;
    }

    /**
     * @dev Sets the royalty information for a specific token id, overriding the global default.
     *
     * Requirements:
     *
     * - `receiver` cannot be the zero address.
     * - `feeNumerator` cannot be greater than the fee denominator.
     */
    function _setTokenRoyalty(
        uint256 tokenId,
        address receiver,
        uint96 feeNumerator
    ) internal virtual {
        require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice");
        require(receiver != address(0), "ERC2981: Invalid parameters");

        _tokenRoyaltyInfo[tokenId] = RoyaltyInfo(receiver, feeNumerator);
    }

    /**
     * @dev Resets royalty information for the token id back to the global default.
     */
    function _resetTokenRoyalty(uint256 tokenId) internal virtual {
        delete _tokenRoyaltyInfo[tokenId];
    }
}

// File: contracts/marketplace/Marketplace.sol


pragma solidity 0.8.17;







contract Marketplace is ReentrancyGuard {
    using SafeERC20 for IERC20;

    enum SaleType {
        FIXED,
        AUCTION,
        NONE,
        OFFER
    }

    enum ItemStatus {
        /* Buy Now */
        SALE_START,
        SALE_REMOVED,
        SALE_SUCCESS,
        /* Auction */
        AUCTION_START,
        AUCTION_SUCCESS,
        AUCTION_REMOVED,
        AUCTION_NEW_BID,
        /* ROYALTY */
        ROYALTY_UPDATED,
        /* SPONTANEOUS OFFER */
        OFFER_START,
        OFFER_SUCCESS,
        OFFER_REMOVED
    }

    struct Royalty {
        address receiver;
        uint256 basisPoints;
    }

    struct Item {
        SaleType saleType;
        uint256 price;
        address tokenAddress;
        address seller;
        address buyer;
        uint256 promiseStartTime; // When the item was created
        /* These are used for auction only */
        uint256 endTime;
        address bidder;
        uint256 bidAmount;
        /* These are used for erc1155 */
        uint256 quantity;
        /* For Private Sale */
        address[] addressesForPrivateSaleList;
    }

    struct Payout {
        uint256 sellerPayout;
        address tokenAddress;
        uint256 marketFee;
        Royalty royalty;
    }

    event MarketplaceEvent(
        ItemStatus itemStatus,
        address collectionAddress,
        uint256 tokenId,
        Item item,
        Payout payout
    );

    event NewTokenEvent(
        address tokenAddress,
        uint256 floorPrice
    );

    event Withdrawal(address walletAddress, uint256 amount, address tokenAddress);

    // Allowed Token Addresses
    mapping (address => uint256) public allowedTokenAddresses;
   
    // ContractAddress => Royalty
    mapping(address => Royalty) public royalties;
    uint256 public maxPrivateSaleListLength = 100;
    uint256 public maxRoyaltyBasisPoints = 1000; 
    uint256 public minWaitTimeToCancel = 3600;

    // AUCTION
    uint256 public minBidIncrementPercent = 10;
    uint256 public minAuctionLength = 3600;
    uint256 public maxAuctionLength = 31449600;

    uint256 public marketPercent = 225;
    uint256 public marketPercentMint = 150;
    address public feeSplitterAddress;
    address public wizard;

    address public mintTokenAddress;
    
    // Wallet Address => Erc20Addres(0 for PLS) => Amount
    mapping(address => mapping(address => uint256)) public pendingWithdrawals;

    modifier onlyWizard() {
        require(
            msg.sender == wizard,
            "Not Wizard"
        );
        _;
    }

    /**
     * @notice Modifier to check if bid conditions are met before allowing a bid
     * @dev Checks the validity of an auction bid before it can be made
     * @param _item Item object containing details of the item being bid on
     */
    modifier checkBidValidity(uint256 _bidAmount, Item memory _item) {
        // Require that the sale type is auction
        require(_item.saleType == SaleType.AUCTION, "Incorrect sale type");

        // Require that the item is actually for sale
        require(_item.seller != address(0), "Item is not on sale");

        // Require that the auction has not ended
        require(_item.endTime != 0, "Auction ended");

        // Require that the auction has not yet ended
        require(block.timestamp <= _item.endTime, "Auction completed");

        
        // Check if we have a previous bid. If not previous bid, the bid can be made at the initial sale price
        if (_item.bidAmount == 0) {
            // Require that the bid amount meets the minimum price
            require(_bidAmount >= _item.price, "Min price not met");

        } else {
            // Require that the bid amount is higher than the current highest bid plus the minimum bid increment
            require(
                _bidAmount >=
                    _item.bidAmount +
                        ((_item.bidAmount * minBidIncrementPercent) / 100),
                "Bid too low"
            );
        }

        _;
    }

    /**
     * @notice Modifier to check if auction conditions are met before creating a new auction
     * @dev Checks the validity of auction parameters before creating a new auction
     * @param _minPrice Minimum price for the auction
     * @param _endTime End time for the auction
     */
    modifier checkAuctionValidity(uint256 _minPrice, uint256 _endTime, address _tokenAddress) {

        uint256 floorPrice = allowedTokenAddresses[_tokenAddress];

        require (floorPrice > 0, "Invalid token address");

        // Require that the minimum price for the auction meets the floor price
        require(_minPrice >= floorPrice, "Min price not met");

        // Require that the auction length is greater than the minimum allowed length
        require(
            _endTime > block.timestamp + minAuctionLength,
            "Auction min length not met"
        );

        // Require that the auction length is less than the maximum allowed length
        require(
            _endTime < block.timestamp + maxAuctionLength,
            "Auction max length not met"
        );

        _;
    }

    /**
     * @notice Creates a new instance of the Marketplace contract
     * @dev Initializes the contract with the addresses of the marketPercentDecreaser and feeSplitterAddress
     * @param _wizard Address wizard
     * @param _feeSplitterAddress Address of the fee splitter contract
     */
    constructor(address _wizard, address _feeSplitterAddress, address _mintTokenAddress) {
        require(_wizard != address(0), "Invalid address");
        require(_feeSplitterAddress != address(0), "Invalid address");
        require(_mintTokenAddress != address(0), "Invalid address");

        wizard = _wizard;
        feeSplitterAddress = _feeSplitterAddress;
        mintTokenAddress = _mintTokenAddress;

        // address(0) is used to represent native PLS
        address allowedAddress = address(0);

        allowedTokenAddresses[allowedAddress] = 1 ether;

        // HEX
        allowedAddress = 0x2b591e99afE9f32eAA6214f7B7629768c40Eeb39;
        allowedTokenAddresses[allowedAddress] = 100000000; // 1
   
        // PEPE
        allowedAddress = 0x6982508145454Ce325dDbE47a25d4ec3d2311933;
        allowedTokenAddresses[allowedAddress] = 1000000000000000000000000; // 1,000,000
    
        // SHIB
        allowedAddress = 0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE;
        allowedTokenAddresses[allowedAddress] = 1000000000000000000000000; // 1,000,000

        // XEN
        allowedAddress = 0x06450dEe7FD2Fb8E39061434BAbCFC05599a6Fb8;
        allowedTokenAddresses[allowedAddress] = 10000000000000000000000000; // 10,000,000
 
        // HDRN
        allowedAddress = 0x3819f64f282bf135d62168C1e513280dAF905e06;
        allowedTokenAddresses[allowedAddress] = 1000000000000000; // 1,000,000

        // ICSA
        allowedAddress = 0xfc4913214444aF5c715cc9F7b52655e788A569ed;
        allowedTokenAddresses[allowedAddress] = 1000000000; // 1
  
        // MAXI
        allowedAddress = 0x0d86EB9f43C57f6FF3BC9E23D8F9d82503f0e84b;
        allowedTokenAddresses[allowedAddress] = 100000000; // 1
 
        // DECI
        allowedAddress = 0x6b32022693210cD2Cfc466b9Ac0085DE8fC34eA6;
        allowedTokenAddresses[allowedAddress] = 100000000; // 1

        // LUCKY
        allowedAddress = 0x6B0956258fF7bd7645aa35369B55B61b8e6d6140;
        allowedTokenAddresses[allowedAddress] = 100000000; // 1

        // TRIO
        allowedAddress = 0xF55cD1e399e1cc3D95303048897a680be3313308;
        allowedTokenAddresses[allowedAddress] = 100000000; // 1
  
        // BASE
        allowedAddress = 0xe9f84d418B008888A992Ff8c6D22389C2C3504e0;
        allowedTokenAddresses[allowedAddress] = 100000000; // 1

        // MINT
        allowedAddress = _mintTokenAddress;
        allowedTokenAddresses[allowedAddress] = 1 ether;
  
        // TIME
        allowedAddress = 0xCA35638A3fdDD02fEC597D8c1681198C06b23F58;
        allowedTokenAddresses[allowedAddress] = 1 ether; // 1
   
        // PHUX
        allowedAddress = 0x9663c2d75ffd5F4017310405fCe61720aF45B829;
        allowedTokenAddresses[allowedAddress] = 1 ether; // 1

        // MORE
        allowedAddress = 0xbEEf3bB9dA340EbdF0f5bae2E85368140d7D85D0;
        allowedTokenAddresses[allowedAddress] = 1 ether; // 1

        // PP
        allowedAddress = 0x9565c2036963697786705120Fc59310F747bCfD0;
        allowedTokenAddresses[allowedAddress] = 10000000000000000000000; // 10,000
 
        // WAIT
        allowedAddress = 0x26179a4d4B58b4456F28d19507546596c9058ee5;
        allowedTokenAddresses[allowedAddress] = 100000000; // 1
 
        // TEXAN
        allowedAddress = 0xcFCFfE432A48dB53F59c301422d2EdD77B2A88d7;
        allowedTokenAddresses[allowedAddress] = 10000000000000000000000; // 10,000
 

    }

    /**
     * @notice Send funds to the proper addresses after a sale
     * @dev Calculates and distributes the funds from a sale to the seller, royalty receiver, and fee splitter
     * @param _seller Address of the seller
     * @param _price Amount of funds to be distributed
     * @param _collectionAddress Address of the collection contract
     * @param _tokenId ID of the token being sold
     * @return _payout A Payout object containing information about the amounts distributed
     */
    function payout(
        address _seller,
        uint256 _price,
        address _tokenAddress,
        address _collectionAddress,
        uint256 _tokenId
    ) internal returns (Payout memory _payout) {
        // Calculate market fee
        
        uint256 marketFee;
        if (_tokenAddress == mintTokenAddress) {
            marketFee = (_price * marketPercentMint) / 10000;
        } else {
            marketFee = (_price * marketPercent) / 10000;
        }

        // Calculate royalty amount and receiver
        uint256 royaltyAmount;
        address royaltyReceiver;

        // Check if collection has royalty using ERC2981
        if (isERC2981(_collectionAddress)) {
            (royaltyReceiver, royaltyAmount) = ERC2981(_collectionAddress)
                .royaltyInfo(_tokenId, _price);

           require(royaltyAmount < _price - marketFee, "Royalty too high");
        } else {
            royaltyAmount =
                (_price * royalties[_collectionAddress].basisPoints) /
                10000;
            royaltyReceiver = royalties[_collectionAddress].receiver;
        }

        // Calculate amount to send to seller
        uint256 sellerAmount = (_price - marketFee) - royaltyAmount;

        // amount to seller
        pendingWithdrawals[_seller][_tokenAddress] += sellerAmount;

        // Send royalty amount to receiver
        if (royaltyAmount > 0) {
            pendingWithdrawals[royaltyReceiver][_tokenAddress] += royaltyAmount;
        }

        // Send market fee to fee splitter.
        if (_tokenAddress == address(0)) {
            (bool success, ) = payable(feeSplitterAddress).call{value: marketFee}("");
            require(success, "Transfer failed");
        } else {
            // Transfer the marketplace fee to the feeSplitterAddress
            IERC20(_tokenAddress).safeTransfer(feeSplitterAddress, marketFee);
        }

        // Return Payout object with information about the amounts distributed
        return Payout(sellerAmount, _tokenAddress, marketFee, royalties[_collectionAddress]);
    }

    function isTokenAllowed(address _tokenAddress) public view returns (bool) {
        return allowedTokenAddresses[_tokenAddress] > 0;
    }

    /**
     * @notice Update the market fee percentage
     * @dev Updates the market fee percentage to a new value
     * @param _marketPercent New value for the market fee percentage
     */
    function setMarketPercent(uint256 _marketPercent) public onlyWizard {
        require(_marketPercent <= 369, "Fee not in range");

        marketPercent = _marketPercent;
    }

    /**
     * @notice Set or update the royalty for a collection
     * @dev Sets or updates the royalty for a collection to a new value
     * @param _collectionAddress Address of the collection to set the royalty for
     * @param _royaltyInBasisPoints New royalty value, in basis points (1 basis point = 0.01%)
     */
    function createOrUpdateRoyalty(
        address _collectionAddress,
        uint256 _royaltyInBasisPoints,
        address receiver
    ) public nonReentrant {
        require(
            _royaltyInBasisPoints <= maxRoyaltyBasisPoints,
            "Royalties cannot exceed maximum"
        );

        require(receiver != address(0), "receiver is not set");

        // Check if the royalty already exists and is being increased
        if (royalties[_collectionAddress].receiver != address(0)) {
            require(
                _royaltyInBasisPoints <=
                    royalties[_collectionAddress].basisPoints,
                "Royalties cannot be increased"
            );
        }

        // Check that the caller is the owner/creator of the collection contract
        require(
            Ownable(_collectionAddress).owner() == msg.sender,
            "Unauthorized"
        );

        // Create a new Royalty object with the given value and store it in the royalties mapping
        Royalty memory royalty = Royalty(receiver, _royaltyInBasisPoints);
        royalties[_collectionAddress] = royalty;

        // Emit a MarketplaceEvent with information about the royalty update
        address[] memory addressesForPrivateSaleList = new address[](0);
        emit MarketplaceEvent(
            ItemStatus.ROYALTY_UPDATED,
            _collectionAddress,
            0,
            Item(
                SaleType.NONE,
                0,
                address(0),
                address(0),
                address(0),
                0,
                0,
                address(0),
                0,
                0,
                addressesForPrivateSaleList
            ),
            Payout(0, address(0), 0, royalty)
        );
    }

    /**
     * @dev If this is a private sale, check that the sender is in the list of addresses
     * @param _item item
     */
    function checkPrivateSale(Item memory _item) internal view {
        if (_item.addressesForPrivateSaleList.length > 0) {
            bool foundMatch = false;

            for (
                uint256 i = 0;
                i < _item.addressesForPrivateSaleList.length;
                i++
            ) {
                if (_item.addressesForPrivateSaleList[i] == msg.sender) {
                    foundMatch = true;
                }
            }

            require(foundMatch, "Not allowed in private sale.");
        }
    }

    /**
     * @dev Check that the length of the private sale list is not too long
     * @param _addressesForPrivateSaleList Array of addresses for the private sale list
     */
    function checkPrivateSaleListLength(
        address[] memory _addressesForPrivateSaleList
    ) internal view {
        require(
            _addressesForPrivateSaleList.length <= maxPrivateSaleListLength,
            "Private sale list too long"
        );
    }

    /**
     * @dev Reimburse the previous bidder for an item
     * @param _item The item to reimburse the bidder for
     */
    function reimbursePreviousBidder(Item memory _item) internal {
        if (_item.bidAmount > 0) {
            // Set the amount to zero before transferring to protect against reentrancy attacks
            uint256 _amount = _item.bidAmount;
            _item.bidAmount = 0;

            pendingWithdrawals[_item.bidder][_item.tokenAddress] += _amount;
        }
    }

    /**
     * @dev Allow a user to retrieve funds for a specified receiver
     */
    function withdraw(address[] memory tokenAddresses, address receiver) external nonReentrant {

        for (uint256 i = 0; i < tokenAddresses.length; i++) {
            uint256 funds = pendingWithdrawals[receiver][tokenAddresses[i]];

            // Withdraw funds
            if (funds > 0) {
                // Delete the stored funds from the mapping
                delete pendingWithdrawals[receiver][tokenAddresses[i]];

                // Are we transfering PLS or an ERC20 token?
                if (tokenAddresses[i] == address(0)) {
                    // Transfer the funds to the caller
                    (bool success, ) = payable(receiver).call{value: funds}("");
                    require(success, "Transfer failed.");
                } else {
                    IERC20(tokenAddresses[i]).safeTransfer(receiver, funds);
                }

                emit Withdrawal(receiver, funds, tokenAddresses[i]);
            }

        }
        
    }

    /**
     * @dev Check if an auction can end
     * @param item The item to check if the auction can end for
     */
    function checkIfAuctionCanEnd(Item memory item) internal view {
        // Check if there is a bid on the item
        if (item.bidAmount == 0) {

            // If there is no bid, the auction can only end after a certain waiting period has elapsed
            require(
                item.promiseStartTime + minWaitTimeToCancel < block.timestamp,
                "Too early to cancel"
            );
        } else {
            // If there is a bid on the item, the auction can only end after the item's end time has passed
            require(block.timestamp > item.endTime, "Auction has not ended");
        }
    }

    /**
     * @notice This function checks if a given contract is ERC2981 compliant
     * @dev This function is called internally and cannot be accessed outside the contract
     * @param _contract The address of the contract to check
     * @return A boolean indicating whether the contract is ERC2981 compliant or not
     */
    function isERC2981(address _contract) internal view returns (bool) {
        try ERC2981(_contract).royaltyInfo(0, 0) returns (address, uint256) {
            return true;
        } catch {
            return false;
        }
    }

    /**
     * @notice This function adds an token address to the allowed list
     * @param erc20Address The address of the token (address(0) for PLS))
     * @param floorPrice The floor price of the token
     */
    function addTokenAddress(address erc20Address, uint256 floorPrice) external onlyWizard {

        require(floorPrice > 0, "Floor price to low");
        require(allowedTokenAddresses[erc20Address] == 0, "Token Already Exists");

        allowedTokenAddresses[erc20Address] = floorPrice;
        emit NewTokenEvent(erc20Address, floorPrice); 
    }
}

// File: @openzeppelin/contracts/token/ERC721/IERC721.sol


// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.0;


/**
 * @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 caller.
     *
     * 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: contracts/marketplace/ERC721Marketplace.sol


pragma solidity 0.8.17;






contract ERC721Marketplace is Marketplace {
    using SafeERC20 for IERC20;

    // ContractAddress => TokenId => Item
    mapping(address => mapping(uint256 => Item)) public items;

    /**
     * @notice Creates a new instance of an ERC721 Marketplace
     * @dev Initializes the Marketplace contract with the provided admin and payee addresses and royalty percentage
     * @param _wizard Address of the market percent decreaser contract
     * @param _feeSplitterAddress Address of the fee splitter contract
     * @param _mintTokenAddress Address of the mint token contract
     */
    constructor(
        address _wizard,
        address _feeSplitterAddress,
        address _mintTokenAddress
    ) Marketplace(_wizard, _feeSplitterAddress, _mintTokenAddress) {     
    }

    /**
     * @notice Lists an item for sale in the marketplace
     * @dev Adds the item to the list of items for sale and sets its price, sale type, and status
     * @param _collectionAddress The address of the collection to which the item belongs
     * @param _tokenId The ID of the item to be listed
     * @param _price The sale price of the item
     * @param privateSaleList The list of addresses to which the item can be sold at a private price
     */
    function putOnSale(
        address _collectionAddress,
        uint256 _tokenId,
        uint256 _price,
        address _tokenAddress,
        address[] calldata privateSaleList
    ) public nonReentrant {

        uint256 floorPrice = allowedTokenAddresses[_tokenAddress];

        require (floorPrice > 0, "floorPrice invalid");

        // Ensure the item is listed above or equal to the floor price
        require(_price >= floorPrice, "floorPrice not met");

        // Get the item from storage using its collection address and token ID
        Item memory item = items[_collectionAddress][_tokenId];

        // If the item is on offer, reimburse the previous bidder
        if (item.saleType == SaleType.OFFER) {
            reimbursePreviousBidder(item);
        } else {
            // If the item is not on offer, ensure it is not already listed
            require(item.seller == address(0), "Item listed");
        }

        // Add the item to the list of items for sale
        listForSale(
            _collectionAddress,
            _tokenId,
            _price,
            _tokenAddress,
            SaleType.FIXED,
            ItemStatus.SALE_START,
            0,
            privateSaleList
        );
    }

    /**
     * @notice Remove a listing for an item in the marketplace
     * @dev Allows the owner of a listed item to remove the item from the marketplace
     * @param _collectionAddress The address of the collection to which the item belongs
     * @param _tokenId The ID of the item to be removed from sale
     */
    function takeOffSale(
        address _collectionAddress,
        uint256 _tokenId
    ) public nonReentrant {
        // Get the item from storage using its collection address and token ID
        Item memory item = items[_collectionAddress][_tokenId];

        // Ensure that the caller is the owner of the item
        require(item.seller == msg.sender, "Not owner of item");

        // Ensure that the minimum time has passed since the item was listed before it can be removed from sale
        require(
            block.timestamp > item.promiseStartTime + minWaitTimeToCancel,
            "Too early to cancel"
        );

        // Transfer the NFT back to the seller
        IERC721 tokenContract = IERC721(_collectionAddress);
        tokenContract.transferFrom(address(this), msg.sender, _tokenId);

        // Delete the item from the list of items for sale
        delete items[_collectionAddress][_tokenId];

        // Emit an event indicating that the sale was removed
        // item.buyer == address(0) because it was taken off sale
        emit MarketplaceEvent(
            ItemStatus.SALE_REMOVED,
            _collectionAddress,
            _tokenId,
            item,
            Payout(0, item.tokenAddress, 0, Royalty(address(0), 0))
        );
    }

    /**
     * @notice Create an auction for an item in the marketplace
     * @dev Allows the owner of an item to create an auction for it, with a specified starting price and end time
     * @param _collectionAddress The address of the collection to which the item belongs
     * @param _tokenId The ID of the item to be auctioned
     * @param _minPrice The starting price of the auction
     * @param _endTime The timestamp at which the auction will end
     * @param privateSaleList The list of addresses to which the item can be sold at a private price
     */
    function putOnAuction(
        address _collectionAddress,
        uint256 _tokenId,
        uint256 _minPrice,
        address _tokenAddress,
        uint256 _endTime,
        address[] calldata privateSaleList
    ) public nonReentrant checkAuctionValidity(_minPrice, _endTime, _tokenAddress) {
  
        // Get the item from storage using its collection address and token ID
        Item memory item = items[_collectionAddress][_tokenId];

        // If the item is on offer, reimburse the previous bidder
        if (item.saleType == SaleType.OFFER) {
            reimbursePreviousBidder(item);
        } else {
            // If the item is not on offer, ensure it is not already listed
            require(item.seller == address(0), "Item already listed");
        }

        // Add the item to the list of items for sale as an auction
        listForSale(
            _collectionAddress,
            _tokenId,
            _minPrice,
            _tokenAddress,
            SaleType.AUCTION,
            ItemStatus.AUCTION_START,
            _endTime,
            privateSaleList
        );
    }

    /**
     * @notice Place a bid on an item listed for auction in the marketplace
     * @dev Allows a buyer to place a bid on an item listed for auction in the marketplace
     * @param _collectionAddress The address of the collection to which the item belongs
     * @param _tokenId The ID of the item to place a bid on
     */
    function createBid(
        address _collectionAddress,
        uint256 _tokenId,
        uint256 _bidAmount
    )
        external
        payable
        nonReentrant
        checkBidValidity(_bidAmount, items[_collectionAddress][_tokenId])
    { 
        // Get the item from storage using its collection address and token ID
        Item memory item = items[_collectionAddress][_tokenId];

        // Check if the item is part of a private sale
        checkPrivateSale(item);

        // Refund the previous bidder
        reimbursePreviousBidder(item);

        // Update the item with the new bidder
        item.bidder = msg.sender;

        if (item.tokenAddress == address(0)) {
            item.bidAmount = msg.value; // PLS Bid

            require(msg.value == _bidAmount, "Bid amount incorrect");
        } else {
            item.bidAmount = _bidAmount; // ERC20 Bid
            IERC20(item.tokenAddress).safeTransferFrom(msg.sender, address(this), _bidAmount);
        }

        // Update the item in storage
        items[_collectionAddress][_tokenId] = item;

        // Emit an event indicating a new bid has been placed on the item
        emit MarketplaceEvent(
            ItemStatus.AUCTION_NEW_BID,
            _collectionAddress,
            _tokenId,
            item,
            Payout(0, item.tokenAddress, 0, Royalty(address(0), 0))
        );
    }

    /**
     * @notice End an auction for an item in the marketplace
     * @dev Allows the owner of an item listed for auction to end the auction, and transfers the item to the highest bidder
     * @param _collectionAddress The address of the collection to which the item belongs
     * @param _tokenId The ID of the item whose auction is ending
     */
    function endAuction(
        address _collectionAddress,
        uint256 _tokenId
    )
        public
        nonReentrant
    {
        require(items[_collectionAddress][_tokenId].saleType == SaleType.AUCTION, "Incorrect type");
        
        // Get the item from storage using its collection address and token ID
        Item memory item = items[_collectionAddress][_tokenId];
        uint256 winningBidAmount = item.bidAmount;

        // If there are no bids, the auction can be cancelled if minWaitTimeToCancel has passed
        checkIfAuctionCanEnd(item);

        // Get the token contract for the item's collection
        IERC721 tokenContract = IERC721(_collectionAddress);

        // Initialize the item status as auction success
        ItemStatus itemStatus = ItemStatus.AUCTION_SUCCESS;

        if (winningBidAmount == 0) {
            // No Bids

            // Transfer the NFT back to the seller
            tokenContract.transferFrom(address(this), item.seller, _tokenId);

            // Set the item status to auction removed
            itemStatus = ItemStatus.AUCTION_REMOVED;
        } else {
            // Set the buyer of the item to the highest bidder
            item.buyer = item.bidder;

            // Transfer the asset to the contract address.
            transferNFTAssets(_collectionAddress, _tokenId, address(this), item.buyer);
        }

        // Set the sale price of the item to the winning bid amount
        item.price = item.bidAmount;

        // Mark the sale as complete
        completeSale(itemStatus, _collectionAddress, _tokenId, item);
    }

    /**
     * @dev List an item for sale in the marketplace
     * @notice Allows the owner of an item to list it for sale in the marketplace
     * @param _collectionAddress The address of the collection to which the item belongs
     * @param _tokenId The ID of the item to list for sale
     * @param _price The price at which to sell the item
     * @param saleType The type of sale to list the item for
     * @param itemStatus The status of the item after being listed for sale
     * @param _endTime The timestamp at which the sale or auction will end
     * @param addressesForPrivateSaleList The list of addresses to which the item can be sold at a private price
     */
    function listForSale(
        address _collectionAddress,
        uint256 _tokenId,
        uint256 _price,
        address _tokenAddress,
        SaleType saleType,
        ItemStatus itemStatus,
        uint256 _endTime,
        address[] memory addressesForPrivateSaleList
    ) private {
        // Ensure the length of the private sale list is not greater than the maximum allowed
        checkPrivateSaleListLength(addressesForPrivateSaleList);

        // Transfer the NFT to the marketplace contract
        IERC721(_collectionAddress).transferFrom(
            msg.sender,
            address(this),
            _tokenId
        );

        // Create a new item object and add it to storage
        Item memory item = Item(
            saleType,
            _price,
            _tokenAddress,
            msg.sender,
            address(0),
            block.timestamp,
            _endTime,
            address(0),
            0,
            1,
            addressesForPrivateSaleList
        );
        items[_collectionAddress][_tokenId] = item;

        // Emit an event indicating that the item has been listed for sale
        emit MarketplaceEvent(
            itemStatus,
            _collectionAddress,
            _tokenId,
            item,
            Payout(0, _tokenAddress, 0, Royalty(address(0), 0))
        );
    }

    /**
     * @dev Complete a sale of an item in the marketplace
     * @notice Allows the owner of an item to complete a sale of it in the marketplace
     * @param _itemStatus The status of the item after the sale is completed
     * @param _collectionAddress The address of the collection to which the item belongs
     * @param _tokenId The ID of the item being sold
     * @param _item The item being sold
     */
    function completeSale(
        ItemStatus _itemStatus,
        address _collectionAddress,
        uint256 _tokenId,
        Item memory _item
    ) private {
        // Check if the item is on the private sale list
        if (_item.saleType == SaleType.FIXED ) {
            checkPrivateSale(_item);
        }

        // Remove the item from storage
        delete items[_collectionAddress][_tokenId];

        // Calculate the payout for the sale
        Payout memory itemPayout;
        if (
            _itemStatus == ItemStatus.SALE_SUCCESS ||
            _itemStatus == ItemStatus.AUCTION_SUCCESS ||
            _itemStatus == ItemStatus.OFFER_SUCCESS
        ) {
            itemPayout = payout(
                _item.seller,
                _item.price,
                _item.tokenAddress,
                _collectionAddress,
                _tokenId
            );
        }

        // Emit an event indicating that the sale is complete
        emit MarketplaceEvent(
            _itemStatus,
            _collectionAddress,
            _tokenId,
            _item,
            itemPayout
        );
    }

    /**
     * @dev Transfer all assets for a sale.
     * @param _collectionAddress NFT collection address
     * @param _tokenId token ID of the NFT
     * @param _owner address of the NFT owner
     * @param buyer address of the NFT buyer
     */
    function transferNFTAssets(
        address _collectionAddress,
        uint256 _tokenId,
        address _owner,
        address buyer
    ) private {
        IERC721 tokenContract = IERC721(_collectionAddress);
        // Transfer the NFT to the buyer address
        tokenContract.transferFrom(_owner, buyer, _tokenId);
    }

    /**
     * @dev Revoke an offer made on an item.
     * @param _collectionAddress NFT collection address
     * @param _tokenId token ID of the NFT
     */
    function revokeOffer(
        address _collectionAddress,
        uint256 _tokenId
    ) nonReentrant external {
        Item memory item = items[_collectionAddress][_tokenId];

        require(item.saleType == SaleType.OFFER, "Not an offer");
        require(item.buyer == msg.sender, "No offer to revoke");
        require(
            block.timestamp > item.promiseStartTime + minWaitTimeToCancel,
            "Too early to cancel"
        );

        // Remove the item from the marketplace
        delete items[_collectionAddress][_tokenId];

        // Reimburse the previous bidder
        reimbursePreviousBidder(item);

        // Emit an event for the offer being revoked
        emit MarketplaceEvent(
            ItemStatus.OFFER_REMOVED,
            _collectionAddress,
            _tokenId,
            item,
            Payout(0, item.tokenAddress, 0, Royalty(address(0), 0))
        );
    }

    /**
     * @notice This function allows a user to make an offer on an NFT item
     * @dev This function can be accessed externally and is non-reentrant
     * @param _collectionAddress The address of the NFT collection
     * @param _tokenId The ID of the NFT item
     */
    function makeOffer(
        address _collectionAddress,
        uint256 _tokenId
    ) external nonReentrant payable {
        // Retrieve the item object from storage
        Item memory item = items[_collectionAddress][_tokenId];

        // Ensure that the item is not already listed for sale
        require(
            item.saleType == SaleType.OFFER || item.seller == address(0),
            "Item already listed"
        );

        // Get the current owner of the item
        address currentOwner = IERC721(_collectionAddress).ownerOf(_tokenId);

        // Ensure that the sender is not the current owner of the item
        require(currentOwner != msg.sender, "Item not owned");

        // Ensure that the offer amount is sufficient
        require(
            msg.value >= 1 ether &&
                msg.value >= item.bidAmount + (item.bidAmount * minBidIncrementPercent) / 100,
            "Insufficient offer amount"
        );

        // Reimburse the previous bidder if there was one
        reimbursePreviousBidder(item);

        // Update the item details with the new offer
        item.saleType = SaleType.OFFER;
        item.bidAmount = msg.value;
        item.bidder = msg.sender;
        item.seller = currentOwner;
        item.buyer = msg.sender;
        item.promiseStartTime = block.timestamp;

        // Update the item object in storage
        items[_collectionAddress][_tokenId] = item;

        // Emit an event to indicate that the offer has been made
        emit MarketplaceEvent(
            ItemStatus.OFFER_START,
            _collectionAddress,
            _tokenId,
            item,
            Payout(0, item.tokenAddress, 0, Royalty(address(0), 0))
        );
    }

    /**
     * @notice This function allows a seller to accept an offer on an NFT item
     * @dev This function can be accessed externally and is non-reentrant
     * @param _collectionAddress The address of the NFT collection
     * @param _tokenId The ID of the NFT item
     */
    function acceptOffer(
        address _collectionAddress,
        uint256 _tokenId
    ) external nonReentrant {
        // Retrieve the item object from storage
        Item memory item = items[_collectionAddress][_tokenId];
        
        // Ensure that the item is listed as an offer
        require(item.saleType == SaleType.OFFER, "No offer available");

        // Transfer the assets to the buyer
        transferNFTAssets(_collectionAddress, _tokenId, msg.sender, item.buyer);

        // Set the sale price of the item to the winning offer amount and the seller
        item.price = item.bidAmount;
        item.seller = msg.sender;

        // Complete the sale and update the analytics
        completeSale(
            ItemStatus.OFFER_SUCCESS,
            _collectionAddress,
            _tokenId,
            item
        );
    }

    /**
     * @dev Puts multiple tokens on sale.
     * @param _collectionAddress The address of the collection.
     * @param _tokenIds An array of token IDs to put on sale.
     * @param _prices An array of sale prices for the tokens.
     * @param _tokenAddresses An array of ERC20 token addresses for the tokens.
     * @param privateSaleList An array of addresses for private sales (optional).
     */
    function bulkPutOnSale(
        address _collectionAddress,
        uint256[] memory _tokenIds,
        uint256[] memory _prices,
        address[] memory _tokenAddresses,
        address[] calldata privateSaleList
    ) external {
        // Make sure that tokenIds, prices and _tokenAddresses match
        require(_tokenIds.length == _prices.length, "Length mismatch");
        require(_prices.length == _tokenAddresses.length, "Length mismatch");

        // Iterate over each tokenId
        for (uint256 i = 0; i < _tokenIds.length; i++) {
            // Call the putOnSale function for the current tokenId
            putOnSale(
                _collectionAddress,
                _tokenIds[i],
                _prices[i],
                _tokenAddresses[i],
                privateSaleList
            );
        }
    }

    /**
     * @dev Takes multiple tokens off sale.
     * @param _collectionAddress The address of the collection.
     * @param _tokenIds An array of token IDs to take off sale.
     */
    function bulkTakeOffSale(
        address _collectionAddress,
        uint256[] memory _tokenIds
    ) external {
        // Iterate over each tokenId
        for (uint256 i = 0; i < _tokenIds.length; i++) {
            // Call the takeOffSale function for the current tokenId
            takeOffSale(_collectionAddress, _tokenIds[i]);
        }
    }

    /**
     * @dev Puts multiple tokens on auction.
     * @param _collectionAddress The address of the collection.
     * @param _tokenIds An array of token IDs to put on auction.
     * @param _minPrices An array of minimum auction prices for the tokens.
     * @param _tokenAddresses An array of ERC20 token addresses.
     * @param _endTimes An array of end times for the auctions.
     * @param privateSaleList An array of addresses for private sales (optional).
     */
    function bulkPutOnAuction(
        address _collectionAddress,
        uint256[] memory _tokenIds,
        uint256[] memory _minPrices,
        address[] memory _tokenAddresses,
        uint256[] memory _endTimes,
        address[] calldata privateSaleList
    ) external {
        // Make sure that tokenIds, minPrices, _tokenAddresses and _endTimes match length
        require(
            _tokenIds.length == _minPrices.length && 
            _tokenIds.length == _tokenAddresses.length &&
            _tokenIds.length == _endTimes.length, 
            "Length mismatch"
        );

        // Iterate over each tokenId
        for (uint256 i = 0; i < _tokenIds.length; i++) {

            address tokenAddress = _tokenAddresses[i];

            // Call the putOnAuction function for the current tokenId
            putOnAuction(
                _collectionAddress,
                _tokenIds[i],
                _minPrices[i],
                tokenAddress,
                _endTimes[i],
                privateSaleList
            );
        }
    }

    /**
     * @dev Takes multiple tokens off auction.
     * @param _collectionAddress The address of the collection.
     * @param _tokenIds An array of token IDs to take off auction.
     */
    function bulkEndAuction(
        address _collectionAddress,
        uint256[] memory _tokenIds
    ) external {
        // Iterate over each tokenId
        for (uint256 i = 0; i < _tokenIds.length; i++) {
            // Call the endAuction function for the current tokenId
            endAuction(
                _collectionAddress,
                _tokenIds[i]
            );
        }
    }

    /**
     * @dev Buy multiple tokens
     * @param _collectionAddress The address of the collection.
     * @param _tokenIds An array of token IDs to put on auction.
     */
    function buy(
        address _collectionAddress,
        uint256[] memory _tokenIds
    ) external payable nonReentrant {
        uint256 totalAmountPls = 0;
        // Iterate over each tokenId
        for (uint256 i = 0; i < _tokenIds.length; i++) {
            // Are we buying this item in PLS
            address tokenAddress = items[_collectionAddress][_tokenIds[i]].tokenAddress;
            uint256 price = items[_collectionAddress][_tokenIds[i]].price;

            if (tokenAddress == address(0)) {
                //calculate total amount for items being sold for PLS
                totalAmountPls += price;
            } else {
                // Transfer ERC20 tokens to this contract
                IERC20(tokenAddress).safeTransferFrom(msg.sender, address(this), price);
            }

            // Call the buy function for the current tokenId
            _buy(_collectionAddress, _tokenIds[i]);
        }

        // Make sure that the total price for items bought with PLS is equal to the amount sent
        require(totalAmountPls == 0 || msg.value == totalAmountPls, "Incorrect");
    }

        /**
     * @notice Buy an item that is listed for sale in the marketplace
     * @dev Allows a buyer to purchase an item listed for sale in the marketplace, and transfers the asset to the buyer's address
     * @param _collectionAddress The address of the collection to which the item belongs
     * @param _tokenId The ID of the item to be purchased
     */
    function _buy(
        address _collectionAddress,
        uint256 _tokenId
    )
        internal
    {
        // Get the item from storage using its collection address and token ID
        Item memory item = items[_collectionAddress][_tokenId];

        require(item.seller != address(0), "Item not on sale");
        
        require(item.saleType == SaleType.FIXED, "Incorrect type");

        // Set the buyer address of the item to the address of the buyer.
        item.buyer = msg.sender;

        // Transfer the asset to the buyer address.
        transferNFTAssets(_collectionAddress, _tokenId, address(this), item.buyer);

        // Mark the sale as complete.
        completeSale(
            ItemStatus.SALE_SUCCESS,
            _collectionAddress,
            _tokenId,
            item
        );
    }
}
        

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_wizard","internalType":"address"},{"type":"address","name":"_feeSplitterAddress","internalType":"address"},{"type":"address","name":"_mintTokenAddress","internalType":"address"}]},{"type":"event","name":"MarketplaceEvent","inputs":[{"type":"uint8","name":"itemStatus","internalType":"enum Marketplace.ItemStatus","indexed":false},{"type":"address","name":"collectionAddress","internalType":"address","indexed":false},{"type":"uint256","name":"tokenId","internalType":"uint256","indexed":false},{"type":"tuple","name":"item","internalType":"struct Marketplace.Item","indexed":false,"components":[{"type":"uint8","name":"saleType","internalType":"enum Marketplace.SaleType"},{"type":"uint256","name":"price","internalType":"uint256"},{"type":"address","name":"tokenAddress","internalType":"address"},{"type":"address","name":"seller","internalType":"address"},{"type":"address","name":"buyer","internalType":"address"},{"type":"uint256","name":"promiseStartTime","internalType":"uint256"},{"type":"uint256","name":"endTime","internalType":"uint256"},{"type":"address","name":"bidder","internalType":"address"},{"type":"uint256","name":"bidAmount","internalType":"uint256"},{"type":"uint256","name":"quantity","internalType":"uint256"},{"type":"address[]","name":"addressesForPrivateSaleList","internalType":"address[]"}]},{"type":"tuple","name":"payout","internalType":"struct Marketplace.Payout","indexed":false,"components":[{"type":"uint256","name":"sellerPayout","internalType":"uint256"},{"type":"address","name":"tokenAddress","internalType":"address"},{"type":"uint256","name":"marketFee","internalType":"uint256"},{"type":"tuple","name":"royalty","internalType":"struct Marketplace.Royalty","components":[{"type":"address","name":"receiver","internalType":"address"},{"type":"uint256","name":"basisPoints","internalType":"uint256"}]}]}],"anonymous":false},{"type":"event","name":"NewTokenEvent","inputs":[{"type":"address","name":"tokenAddress","internalType":"address","indexed":false},{"type":"uint256","name":"floorPrice","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Withdrawal","inputs":[{"type":"address","name":"walletAddress","internalType":"address","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false},{"type":"address","name":"tokenAddress","internalType":"address","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"acceptOffer","inputs":[{"type":"address","name":"_collectionAddress","internalType":"address"},{"type":"uint256","name":"_tokenId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addTokenAddress","inputs":[{"type":"address","name":"erc20Address","internalType":"address"},{"type":"uint256","name":"floorPrice","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"allowedTokenAddresses","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"bulkEndAuction","inputs":[{"type":"address","name":"_collectionAddress","internalType":"address"},{"type":"uint256[]","name":"_tokenIds","internalType":"uint256[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"bulkPutOnAuction","inputs":[{"type":"address","name":"_collectionAddress","internalType":"address"},{"type":"uint256[]","name":"_tokenIds","internalType":"uint256[]"},{"type":"uint256[]","name":"_minPrices","internalType":"uint256[]"},{"type":"address[]","name":"_tokenAddresses","internalType":"address[]"},{"type":"uint256[]","name":"_endTimes","internalType":"uint256[]"},{"type":"address[]","name":"privateSaleList","internalType":"address[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"bulkPutOnSale","inputs":[{"type":"address","name":"_collectionAddress","internalType":"address"},{"type":"uint256[]","name":"_tokenIds","internalType":"uint256[]"},{"type":"uint256[]","name":"_prices","internalType":"uint256[]"},{"type":"address[]","name":"_tokenAddresses","internalType":"address[]"},{"type":"address[]","name":"privateSaleList","internalType":"address[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"bulkTakeOffSale","inputs":[{"type":"address","name":"_collectionAddress","internalType":"address"},{"type":"uint256[]","name":"_tokenIds","internalType":"uint256[]"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"buy","inputs":[{"type":"address","name":"_collectionAddress","internalType":"address"},{"type":"uint256[]","name":"_tokenIds","internalType":"uint256[]"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"createBid","inputs":[{"type":"address","name":"_collectionAddress","internalType":"address"},{"type":"uint256","name":"_tokenId","internalType":"uint256"},{"type":"uint256","name":"_bidAmount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"createOrUpdateRoyalty","inputs":[{"type":"address","name":"_collectionAddress","internalType":"address"},{"type":"uint256","name":"_royaltyInBasisPoints","internalType":"uint256"},{"type":"address","name":"receiver","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"endAuction","inputs":[{"type":"address","name":"_collectionAddress","internalType":"address"},{"type":"uint256","name":"_tokenId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"feeSplitterAddress","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isTokenAllowed","inputs":[{"type":"address","name":"_tokenAddress","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint8","name":"saleType","internalType":"enum Marketplace.SaleType"},{"type":"uint256","name":"price","internalType":"uint256"},{"type":"address","name":"tokenAddress","internalType":"address"},{"type":"address","name":"seller","internalType":"address"},{"type":"address","name":"buyer","internalType":"address"},{"type":"uint256","name":"promiseStartTime","internalType":"uint256"},{"type":"uint256","name":"endTime","internalType":"uint256"},{"type":"address","name":"bidder","internalType":"address"},{"type":"uint256","name":"bidAmount","internalType":"uint256"},{"type":"uint256","name":"quantity","internalType":"uint256"}],"name":"items","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"makeOffer","inputs":[{"type":"address","name":"_collectionAddress","internalType":"address"},{"type":"uint256","name":"_tokenId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"marketPercent","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"marketPercentMint","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maxAuctionLength","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maxPrivateSaleListLength","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maxRoyaltyBasisPoints","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"minAuctionLength","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"minBidIncrementPercent","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"minWaitTimeToCancel","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"mintTokenAddress","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"pendingWithdrawals","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"putOnAuction","inputs":[{"type":"address","name":"_collectionAddress","internalType":"address"},{"type":"uint256","name":"_tokenId","internalType":"uint256"},{"type":"uint256","name":"_minPrice","internalType":"uint256"},{"type":"address","name":"_tokenAddress","internalType":"address"},{"type":"uint256","name":"_endTime","internalType":"uint256"},{"type":"address[]","name":"privateSaleList","internalType":"address[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"putOnSale","inputs":[{"type":"address","name":"_collectionAddress","internalType":"address"},{"type":"uint256","name":"_tokenId","internalType":"uint256"},{"type":"uint256","name":"_price","internalType":"uint256"},{"type":"address","name":"_tokenAddress","internalType":"address"},{"type":"address[]","name":"privateSaleList","internalType":"address[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"revokeOffer","inputs":[{"type":"address","name":"_collectionAddress","internalType":"address"},{"type":"uint256","name":"_tokenId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"receiver","internalType":"address"},{"type":"uint256","name":"basisPoints","internalType":"uint256"}],"name":"royalties","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMarketPercent","inputs":[{"type":"uint256","name":"_marketPercent","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"takeOffSale","inputs":[{"type":"address","name":"_collectionAddress","internalType":"address"},{"type":"uint256","name":"_tokenId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdraw","inputs":[{"type":"address[]","name":"tokenAddresses","internalType":"address[]"},{"type":"address","name":"receiver","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"wizard","inputs":[]}]
              

Contract Creation Code

Verify & Publish
0x608060405260646003556103e8600455610e10600555600a600655610e106007556301dfe20060085560e16009556096600a553480156200003f57600080fd5b506040516200543e3803806200543e833981016040819052620000629162000496565b60016000558282826001600160a01b038316620000b85760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206164647265737360881b60448201526064015b60405180910390fd5b6001600160a01b038216620001025760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206164647265737360881b6044820152606401620000af565b6001600160a01b0381166200014c5760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206164647265737360881b6044820152606401620000af565b600c80546001600160a01b03199081166001600160a01b0395861617909155600b8054821693851693909317909255600d8054909216921691821790556001602052670de0b6b3a76400007fa6eef7e35abe7026729641147f7915573c7e97b47efa546f5f6e3230263bcb498190556305f5e1007f8087ca14f793394eb82b8652d6e9c3a44da1a27a46582fb6236ea4582a27ef3c81905569d3c21bcecceda10000007fa2fe70d6706770664bd16fda8d19e53f47ff0da9f9efbdcac0b61f87778275f98190557f0764f068385ec30ae72851a17c45ef5bd157e63e9b1ad1bb9c91a81edb63ae78556a084595161401484a0000007ff1eb24505f906c7cc6816fc7dc06cde71b4ef992293453a0f7127f2083f2f0ba5566038d7ea4c680007fd3391033916cafcc2bd44185b1cd70667e2e64d8a1d126a6c6eae836e6fb6f9d55633b9aca007fd70e2f19df8f21c258b74dad31f064ae557e8fba991aad539be10b23c3c4e260557f2e48d770a665a4087de88f6073fc878274b52a0c54f4849f0cb913696a5658348190557f4ff012b224ae6f9d99733f4ff92f321549e681c1daf3ba19d1309d746b54daf48190557fed00c2926164af8bba61161589d0ea9a4ce0161e0641a498bc82bb705db9d10a8190557ff498bcb2d9a8be87aeb7077f0b9257c1652aa330fd321d122da5e51960995df88190557f273a05fc15408f08d8e007661b1952b65d4c824f61592f14cc12af2348b1ab958190556000928352604083208290557f0875fb5a1afcaaa3ebc986ded762ca0a2720dda5e1cad12787a6aa87b8ecac788290557f2602f2074974b61a91c303fc3fe0dac9ae33bc60829dc540a4d25fd1a3905abc8290557f945b41f552824328dc468b896463471d4b4774b2d4c391f7a4fb5d073438ad099190915569021e19e0c9bab24000007f8d70422e2cc52fd9911a2c1682dcff573d9115f1ded461ec4e691b686ea06aee8190557f13f6cf99524de89b93bb4a252b9603e8197ef358dbcbd580a2985dec127af6ba9190915573cfcffe432a48db53f59c301422d2edd77b2a88d79091527f36d54552630c029bbd7fc731af74d997fe756e91e81dfee7f4df1e79d4afb1fd5550620004e0915050565b80516001600160a01b03811681146200049157600080fd5b919050565b600080600060608486031215620004ac57600080fd5b620004b78462000479565b9250620004c76020850162000479565b9150620004d76040850162000479565b90509250925092565b614f4e80620004f06000396000f3fe6080604052600436106101fe5760003560e01c80639fa6b4a01161011d578063cac025c4116100b0578063ea7a25171161007f578063f9af8b3811610064578063f9af8b381461066c578063f9eaee0d1461068c578063fba133d9146106d457600080fd5b8063ea7a25171461061f578063ee8d4b8e1461064c57600080fd5b8063cac025c414610591578063e1671a0d146105a7578063e6115c64146105c7578063e831be58146105e757600080fd5b8063b1b9e78d116100ec578063b1b9e78d14610528578063b2a4706e14610548578063b5fc53121461055b578063c18aca341461057b57600080fd5b80639fa6b4a014610480578063a0b335e3146104df578063a5ec9c1b146104f5578063aabbbd651461050857600080fd5b8063770915e111610195578063897a849b11610164578063897a849b14610414578063947234951461042a578063978c0bef1461044a5780639e9057951461046a57600080fd5b8063770915e11461037c5780637e3647a9146103b457806381874e51146103d457806388cedbc4146103f457600080fd5b8063460a38cb116101d1578063460a38cb146102845780635c80a435146102a457806364e11d7414610346578063737ab3e31461036657600080fd5b80630556f4f3146102035780630e519ef91461022c578063157620ab1461024257806337d92e7a14610264575b600080fd5b34801561020f57600080fd5b5061021960095481565b6040519081526020015b60405180910390f35b34801561023857600080fd5b5061021960085481565b34801561024e57600080fd5b5061026261025d3660046145da565b6106e7565b005b34801561027057600080fd5b5061026261027f366004614687565b610964565b34801561029057600080fd5b5061026261029f3660046146d7565b6109aa565b3480156102b057600080fd5b506103306102bf3660046146f0565b600f602090815260009283526040808420909152908252902080546001820154600283015460038401546004850154600586015460068701546007880154600889015460099099015460ff9098169896976001600160a01b039687169795871696948516959394929391909216918a565b6040516102239a9998979695949392919061475f565b34801561035257600080fd5b506102626103613660046147c1565b610a5b565b34801561037257600080fd5b5061021960045481565b34801561038857600080fd5b50600b5461039c906001600160a01b031681565b6040516001600160a01b039091168152602001610223565b3480156103c057600080fd5b506102626103cf36600461484f565b610d83565b3480156103e057600080fd5b506102626103ef366004614687565b610ea5565b34801561040057600080fd5b5061026261040f3660046146f0565b610ee6565b34801561042057600080fd5b5061021960065481565b34801561043657600080fd5b506102626104453660046146f0565b61119f565b34801561045657600080fd5b50610262610465366004614915565b611583565b34801561047657600080fd5b5061021960055481565b34801561048c57600080fd5b506104c061049b36600461497f565b600260205260009081526040902080546001909101546001600160a01b039091169082565b604080516001600160a01b039093168352602083019190915201610223565b3480156104eb57600080fd5b5061021960075481565b610262610503366004614687565b611861565b34801561051457600080fd5b50600c5461039c906001600160a01b031681565b34801561053457600080fd5b506102626105433660046146f0565b6119fb565b6102626105563660046146f0565b611bd7565b34801561056757600080fd5b50600d5461039c906001600160a01b031681565b34801561058757600080fd5b5061021960035481565b34801561059d57600080fd5b50610219600a5481565b3480156105b357600080fd5b506102626105c23660046149a3565b6120fd565b3480156105d357600080fd5b506102626105e2366004614a8c565b612209565b3480156105f357600080fd5b50610219610602366004614aff565b600e60209081526000928352604080842090915290825290205481565b34801561062b57600080fd5b5061021961063a36600461497f565b60016020526000908152604090205481565b34801561065857600080fd5b506102626106673660046146f0565b61259e565b34801561067857600080fd5b506102626106873660046146f0565b612972565b34801561069857600080fd5b506106c46106a736600461497f565b6001600160a01b0316600090815260016020526040902054151590565b6040519015158152602001610223565b6102626106e2366004614b2d565b612ada565b6106ef613219565b60005b8251811015610955576001600160a01b0382166000908152600e602052604081208451829086908590811061072957610729614b62565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000205490506000811115610942576001600160a01b0383166000908152600e60205260408120855190919086908590811061078c5761078c614b62565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000206000905560006001600160a01b03168483815181106107d5576107d5614b62565b60200260200101516001600160a01b031603610899576000836001600160a01b03168260405160006040518083038185875af1925050503d8060008114610838576040519150601f19603f3d011682016040523d82523d6000602084013e61083d565b606091505b50509050806108935760405162461bcd60e51b815260206004820152601060248201527f5472616e73666572206661696c65642e0000000000000000000000000000000060448201526064015b60405180910390fd5b506108d0565b6108d083828685815181106108b0576108b0614b62565b60200260200101516001600160a01b03166132729092919063ffffffff16565b7e1a143d5b175701cb3246058ffac3d63945192075a926ff73a19930f09d587a838286858151811061090457610904614b62565b6020026020010151604051610939939291906001600160a01b0393841681526020810192909252909116604082015260600190565b60405180910390a15b508061094d81614bc0565b9150506106f2565b506109606001600055565b5050565b60005b81518110156109a5576109938383838151811061098657610986614b62565b6020026020010151610ee6565b8061099d81614bc0565b915050610967565b505050565b600c546001600160a01b03163314610a045760405162461bcd60e51b815260206004820152600a60248201527f4e6f742057697a61726400000000000000000000000000000000000000000000604482015260640161088a565b610171811115610a565760405162461bcd60e51b815260206004820152601060248201527f466565206e6f7420696e2072616e676500000000000000000000000000000000604482015260640161088a565b600955565b610a63613219565b600454821115610ab55760405162461bcd60e51b815260206004820152601f60248201527f526f79616c746965732063616e6e6f7420657863656564206d6178696d756d00604482015260640161088a565b6001600160a01b038116610b0b5760405162461bcd60e51b815260206004820152601360248201527f7265636569766572206973206e6f742073657400000000000000000000000000604482015260640161088a565b6001600160a01b038381166000908152600260205260409020541615610b96576001600160a01b038316600090815260026020526040902060010154821115610b965760405162461bcd60e51b815260206004820152601d60248201527f526f79616c746965732063616e6e6f7420626520696e63726561736564000000604482015260640161088a565b336001600160a01b0316836001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bde573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c029190614bf8565b6001600160a01b031614610c585760405162461bcd60e51b815260206004820152600c60248201527f556e617574686f72697a65640000000000000000000000000000000000000000604482015260640161088a565b6040805180820182526001600160a01b038381168252602080830186815287831660009081526002808452868220865181547fffffffffffffffffffffffff000000000000000000000000000000000000000016961695909517855591516001909401939093558451838152610180810186528083019182528086018490526060808201859052608080830186905260a0830186905260c0830186905260e08301869052610100830186905261012083018690526101408301869052610160830183905287519081018852858152938401859052838701859052830185905294519394937f6394c5b8350821907b88cf72ed5740bb13cc27d962a0868c3efe34a9a8045f1993610d6f936007938b93909190614d3c565b60405180910390a150506109a56001600055565b8351855114610dd45760405162461bcd60e51b815260206004820152600f60248201527f4c656e677468206d69736d617463680000000000000000000000000000000000604482015260640161088a565b8251845114610e255760405162461bcd60e51b815260206004820152600f60248201527f4c656e677468206d69736d617463680000000000000000000000000000000000604482015260640161088a565b60005b8551811015610e9c57610e8a87878381518110610e4757610e47614b62565b6020026020010151878481518110610e6157610e61614b62565b6020026020010151878581518110610e7b57610e7b614b62565b60200260200101518787611583565b80610e9481614bc0565b915050610e28565b50505050505050565b60005b81518110156109a557610ed483838381518110610ec757610ec7614b62565b602002602001015161119f565b80610ede81614bc0565b915050610ea8565b610eee613219565b60016001600160a01b0383166000908152600f6020908152604080832085845290915290205460ff166003811115610f2857610f2861471c565b14610f755760405162461bcd60e51b815260206004820152600e60248201527f496e636f72726563742074797065000000000000000000000000000000000000604482015260640161088a565b6001600160a01b0382166000908152600f60209081526040808320848452909152808220815161016081019092528054829060ff166003811115610fbb57610fbb61471c565b6003811115610fcc57610fcc61471c565b8152600182015460208083019190915260028301546001600160a01b03908116604080850191909152600385015482166060850152600485015482166080850152600585015460a0850152600685015460c0850152600785015490911660e084015260088401546101008401526009840154610120840152600a8401805482518185028101850190935280835261014090940193919290919083018282801561109e57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611080575b505050919092525050506101008101519091506110ba82613339565b83600460008390036111565760608401516040517f23b872dd0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b03918216602482015260448101879052908316906323b872dd90606401600060405180830381600087803b15801561113557600080fd5b505af1158015611149573d6000803e3d6000fd5b505050506005905061117a565b60e08401516001600160a01b03166080850181905261117a908790879030906133fc565b610100840151602085015261119181878787613489565b505050506109606001600055565b6111a7613219565b6001600160a01b0382166000908152600f60209081526040808320848452909152808220815161016081019092528054829060ff1660038111156111ed576111ed61471c565b60038111156111fe576111fe61471c565b8152600182015460208083019190915260028301546001600160a01b03908116604080850191909152600385015482166060850152600485015482166080850152600585015460a0850152600685015460c0850152600785015490911660e084015260088401546101008401526009840154610120840152600a840180548251818502810185019093528083526101409094019391929091908301828280156112d057602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116112b2575b5050505050815250509050336001600160a01b031681606001516001600160a01b0316146113405760405162461bcd60e51b815260206004820152601160248201527f4e6f74206f776e6572206f66206974656d000000000000000000000000000000604482015260640161088a565b6005548160a001516113529190614db9565b42116113a05760405162461bcd60e51b815260206004820152601360248201527f546f6f206561726c7920746f2063616e63656c00000000000000000000000000604482015260640161088a565b6040517f23b872dd0000000000000000000000000000000000000000000000000000000081523060048201523360248201526044810183905283906001600160a01b038216906323b872dd90606401600060405180830381600087803b15801561140957600080fd5b505af115801561141d573d6000803e3d6000fd5b5050506001600160a01b0385166000908152600f60209081526040808320878452909152812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168155600181018290556002810180547fffffffffffffffffffffffff0000000000000000000000000000000000000000908116909155600382018054821690556004820180548216905560058201839055600682018390556007820180549091169055600881018290556009810182905591506114e7600a8301826143f4565b50507f6394c5b8350821907b88cf72ed5740bb13cc27d962a0868c3efe34a9a8045f19600185858560405180608001604052806000815260200188604001516001600160a01b0316815260200160008152602001604051806040016040528060006001600160a01b03168152602001600081525081525060405161156f959493929190614d3c565b60405180910390a150506109606001600055565b61158b613219565b6001600160a01b038316600090815260016020526040902054806115f15760405162461bcd60e51b815260206004820152601260248201527f666c6f6f72507269636520696e76616c69640000000000000000000000000000604482015260640161088a565b808510156116415760405162461bcd60e51b815260206004820152601260248201527f666c6f6f725072696365206e6f74206d65740000000000000000000000000000604482015260640161088a565b6001600160a01b0387166000908152600f60209081526040808320898452909152808220815161016081019092528054829060ff1660038111156116875761168761471c565b60038111156116985761169861471c565b8152600182015460208083019190915260028301546001600160a01b03908116604080850191909152600385015482166060850152600485015482166080850152600585015460a0850152600685015460c0850152600785015490911660e084015260088401546101008401526009840154610120840152600a8401805482518185028101850190935280835261014090940193919290919083018282801561176a57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161174c575b50505050508152505090506003808111156117875761178761471c565b8151600381111561179a5761179a61471c565b036117ad576117a88161365f565b611808565b60608101516001600160a01b0316156118085760405162461bcd60e51b815260206004820152600b60248201527f4974656d206c6973746564000000000000000000000000000000000000000000604482015260640161088a565b61184d8888888860008060008b8b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506136bd92505050565b50506118596001600055565b505050505050565b611869613219565b6000805b82518110156119a2576001600160a01b0384166000908152600f60205260408120845182908690859081106118a4576118a4614b62565b6020026020010151815260200190815260200160002060020160009054906101000a90046001600160a01b031690506000600f6000876001600160a01b03166001600160a01b03168152602001908152602001600020600086858151811061190e5761190e614b62565b6020026020010151815260200190815260200160002060010154905060006001600160a01b0316826001600160a01b0316036119555761194e8185614db9565b935061196a565b61196a6001600160a01b038316333084613985565b61198d8686858151811061198057611980614b62565b60200260200101516139dc565b5050808061199a90614bc0565b91505061186d565b508015806119af57508034145b6109555760405162461bcd60e51b815260206004820152600960248201527f496e636f72726563740000000000000000000000000000000000000000000000604482015260640161088a565b611a03613219565b6001600160a01b0382166000908152600f60209081526040808320848452909152808220815161016081019092528054829060ff166003811115611a4957611a4961471c565b6003811115611a5a57611a5a61471c565b8152600182015460208083019190915260028301546001600160a01b03908116604080850191909152600385015482166060850152600485015482166080850152600585015460a0850152600685015460c0850152600785015490911660e084015260088401546101008401526009840154610120840152600a84018054825181850281018501909352808352610140909401939192909190830182828015611b2c57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611b0e575b5050505050815250509050600380811115611b4957611b4961471c565b81516003811115611b5c57611b5c61471c565b14611ba95760405162461bcd60e51b815260206004820152601260248201527f4e6f206f6666657220617661696c61626c650000000000000000000000000000604482015260640161088a565b611bb983833384608001516133fc565b61010081015160208201523360608201526109556009848484613489565b611bdf613219565b6001600160a01b0382166000908152600f60209081526040808320848452909152808220815161016081019092528054829060ff166003811115611c2557611c2561471c565b6003811115611c3657611c3661471c565b8152600182015460208083019190915260028301546001600160a01b03908116604080850191909152600385015482166060850152600485015482166080850152600585015460a0850152600685015460c0850152600785015490911660e084015260088401546101008401526009840154610120840152600a84018054825181850281018501909352808352610140909401939192909190830182828015611d0857602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611cea575b5050505050815250509050600380811115611d2557611d2561471c565b81516003811115611d3857611d3861471c565b1480611d4f575060608101516001600160a01b0316155b611d9b5760405162461bcd60e51b815260206004820152601360248201527f4974656d20616c7265616479206c697374656400000000000000000000000000604482015260640161088a565b6040517f6352211e000000000000000000000000000000000000000000000000000000008152600481018390526000906001600160a01b03851690636352211e90602401602060405180830381865afa158015611dfc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e209190614bf8565b9050336001600160a01b03821603611e7a5760405162461bcd60e51b815260206004820152600e60248201527f4974656d206e6f74206f776e6564000000000000000000000000000000000000604482015260640161088a565b670de0b6b3a76400003410158015611ec057506064600654836101000151611ea29190614dd2565b611eac9190614de9565b826101000151611ebc9190614db9565b3410155b611f0c5760405162461bcd60e51b815260206004820152601960248201527f496e73756666696369656e74206f6666657220616d6f756e7400000000000000604482015260640161088a565b611f158261365f565b6003808352346101008401523360e084018190526001600160a01b03838116606086015260808501919091524260a085015285166000908152600f60209081526040808320878452909152902083518154859383917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016906001908490811115611fa157611fa161471c565b0217905550602082810151600183015560408301516002830180546001600160a01b039283167fffffffffffffffffffffffff0000000000000000000000000000000000000000918216179091556060850151600385018054918416918316919091179055608085015160048501805491841691831691909117905560a0850151600585015560c0850151600685015560e085015160078501805491909316911617905561010083015160088301556101208301516009830155610140830151805161207392600a8501920190614412565b509050507f6394c5b8350821907b88cf72ed5740bb13cc27d962a0868c3efe34a9a8045f19600885858560405180608001604052806000815260200188604001516001600160a01b0316815260200160008152602001604051806040016040528060006001600160a01b03168152602001600081525081525060405161156f959493929190614d3c565b8451865114801561210f575083518651145b801561211c575082518651145b6121685760405162461bcd60e51b815260206004820152600f60248201527f4c656e677468206d69736d617463680000000000000000000000000000000000604482015260640161088a565b60005b86518110156121ff57600085828151811061218857612188614b62565b602002602001015190506121ec898984815181106121a8576121a8614b62565b60200260200101518985815181106121c2576121c2614b62565b6020026020010151848987815181106121dd576121dd614b62565b60200260200101518989612209565b50806121f781614bc0565b91505061216b565b5050505050505050565b612211613219565b6001600160a01b0384166000908152600160205260409020548590849086908061227d5760405162461bcd60e51b815260206004820152601560248201527f496e76616c696420746f6b656e20616464726573730000000000000000000000604482015260640161088a565b808410156122cd5760405162461bcd60e51b815260206004820152601160248201527f4d696e207072696365206e6f74206d6574000000000000000000000000000000604482015260640161088a565b6007546122da9042614db9565b83116123285760405162461bcd60e51b815260206004820152601a60248201527f41756374696f6e206d696e206c656e677468206e6f74206d6574000000000000604482015260640161088a565b6008546123359042614db9565b83106123835760405162461bcd60e51b815260206004820152601a60248201527f41756374696f6e206d6178206c656e677468206e6f74206d6574000000000000604482015260640161088a565b6001600160a01b038b166000908152600f602090815260408083208d8452909152808220815161016081019092528054829060ff1660038111156123c9576123c961471c565b60038111156123da576123da61471c565b8152600182015460208083019190915260028301546001600160a01b03908116604080850191909152600385015482166060850152600485015482166080850152600585015460a0850152600685015460c0850152600785015490911660e084015260088401546101008401526009840154610120840152600a840180548251818502810185019093528083526101409094019391929091908301828280156124ac57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161248e575b50505050508152505090506003808111156124c9576124c961471c565b815160038111156124dc576124dc61471c565b036124ef576124ea8161365f565b61254a565b60608101516001600160a01b03161561254a5760405162461bcd60e51b815260206004820152601360248201527f4974656d20616c7265616479206c697374656400000000000000000000000000604482015260640161088a565b61258f8c8c8c8c600160038e8e8e808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506136bd92505050565b5050505050610e9c6001600055565b6125a6613219565b6001600160a01b0382166000908152600f60209081526040808320848452909152808220815161016081019092528054829060ff1660038111156125ec576125ec61471c565b60038111156125fd576125fd61471c565b8152600182015460208083019190915260028301546001600160a01b03908116604080850191909152600385015482166060850152600485015482166080850152600585015460a0850152600685015460c0850152600785015490911660e084015260088401546101008401526009840154610120840152600a840180548251818502810185019093528083526101409094019391929091908301828280156126cf57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116126b1575b50505050508152505090506003808111156126ec576126ec61471c565b815160038111156126ff576126ff61471c565b1461274c5760405162461bcd60e51b815260206004820152600c60248201527f4e6f7420616e206f666665720000000000000000000000000000000000000000604482015260640161088a565b60808101516001600160a01b031633146127a85760405162461bcd60e51b815260206004820152601260248201527f4e6f206f6666657220746f207265766f6b650000000000000000000000000000604482015260640161088a565b6005548160a001516127ba9190614db9565b42116128085760405162461bcd60e51b815260206004820152601360248201527f546f6f206561726c7920746f2063616e63656c00000000000000000000000000604482015260640161088a565b6001600160a01b0383166000908152600f60209081526040808320858452909152812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168155600181018290556002810180547fffffffffffffffffffffffff00000000000000000000000000000000000000009081169091556003820180548216905560048201805482169055600582018390556006820183905560078201805490911690556008810182905560098101829055906128ce600a8301826143f4565b50506128d98161365f565b7f6394c5b8350821907b88cf72ed5740bb13cc27d962a0868c3efe34a9a8045f19600a84848460405180608001604052806000815260200187604001516001600160a01b0316815260200160008152602001604051806040016040528060006001600160a01b03168152602001600081525081525060405161295f959493929190614d3c565b60405180910390a1506109606001600055565b600c546001600160a01b031633146129cc5760405162461bcd60e51b815260206004820152600a60248201527f4e6f742057697a61726400000000000000000000000000000000000000000000604482015260640161088a565b60008111612a1c5760405162461bcd60e51b815260206004820152601260248201527f466c6f6f7220707269636520746f206c6f770000000000000000000000000000604482015260640161088a565b6001600160a01b03821660009081526001602052604090205415612a825760405162461bcd60e51b815260206004820152601460248201527f546f6b656e20416c726561647920457869737473000000000000000000000000604482015260640161088a565b6001600160a01b038216600081815260016020908152604091829020849055815192835282018390527f5f798757cbe0f16e7270bbb4823573adf7c4ae480b5a6428dd9be62a06048d57910160405180910390a15050565b612ae2613219565b6001600160a01b0383166000908152600f602090815260408083208584529091529081902081516101608101909252805483929190829060ff166003811115612b2d57612b2d61471c565b6003811115612b3e57612b3e61471c565b8152600182015460208083019190915260028301546001600160a01b03908116604080850191909152600385015482166060850152600485015482166080850152600585015460a0850152600685015460c0850152600785015490911660e084015260088401546101008401526009840154610120840152600a84018054825181850281018501909352808352610140909401939192909190830182828015612c1057602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612bf2575b505050919092525060019150612c239050565b81516003811115612c3657612c3661471c565b14612c835760405162461bcd60e51b815260206004820152601360248201527f496e636f72726563742073616c65207479706500000000000000000000000000604482015260640161088a565b60608101516001600160a01b0316612cdd5760405162461bcd60e51b815260206004820152601360248201527f4974656d206973206e6f74206f6e2073616c6500000000000000000000000000604482015260640161088a565b8060c00151600003612d315760405162461bcd60e51b815260206004820152600d60248201527f41756374696f6e20656e64656400000000000000000000000000000000000000604482015260640161088a565b8060c00151421115612d855760405162461bcd60e51b815260206004820152601160248201527f41756374696f6e20636f6d706c65746564000000000000000000000000000000604482015260640161088a565b806101000151600003612deb578060200151821015612de65760405162461bcd60e51b815260206004820152601160248201527f4d696e207072696365206e6f74206d6574000000000000000000000000000000604482015260640161088a565b612e69565b6064600654826101000151612e009190614dd2565b612e0a9190614de9565b816101000151612e1a9190614db9565b821015612e695760405162461bcd60e51b815260206004820152600b60248201527f42696420746f6f206c6f77000000000000000000000000000000000000000000604482015260640161088a565b6001600160a01b0385166000908152600f60209081526040808320878452909152808220815161016081019092528054829060ff166003811115612eaf57612eaf61471c565b6003811115612ec057612ec061471c565b8152600182015460208083019190915260028301546001600160a01b03908116604080850191909152600385015482166060850152600485015482166080850152600585015460a0850152600685015460c0850152600785015490911660e084015260088401546101008401526009840154610120840152600a84018054825181850281018501909352808352610140909401939192909190830182828015612f9257602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612f74575b5050505050815250509050612fa681613bf2565b612faf8161365f565b3360e082015260408101516001600160a01b031661302357346101008201819052841461301e5760405162461bcd60e51b815260206004820152601460248201527f42696420616d6f756e7420696e636f7272656374000000000000000000000000604482015260640161088a565b613045565b61010081018490526040810151613045906001600160a01b0316333087613985565b6001600160a01b0386166000908152600f602090815260408083208884529091529020815181548392919082907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660018360038111156130a8576130a861471c565b0217905550602082810151600183015560408301516002830180546001600160a01b039283167fffffffffffffffffffffffff0000000000000000000000000000000000000000918216179091556060850151600385018054918416918316919091179055608085015160048501805491841691831691909117905560a0850151600585015560c0850151600685015560e085015160078501805491909316911617905561010083015160088301556101208301516009830155610140830151805161317a92600a8501920190614412565b509050507f6394c5b8350821907b88cf72ed5740bb13cc27d962a0868c3efe34a9a8045f19600687878460405180608001604052806000815260200187604001516001600160a01b0316815260200160008152602001604051806040016040528060006001600160a01b031681526020016000815250815250604051613204959493929190614d3c565b60405180910390a15050506109a56001600055565b60026000540361326b5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161088a565b6002600055565b6040516001600160a01b0383166024820152604481018290526109a59084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152613cac565b8061010001516000036133a957426005548260a001516133599190614db9565b106133a65760405162461bcd60e51b815260206004820152601360248201527f546f6f206561726c7920746f2063616e63656c00000000000000000000000000604482015260640161088a565b50565b8060c0015142116133a65760405162461bcd60e51b815260206004820152601560248201527f41756374696f6e20686173206e6f7420656e6465640000000000000000000000604482015260640161088a565b6040517f23b872dd0000000000000000000000000000000000000000000000000000000081526001600160a01b0383811660048301528281166024830152604482018590528591908216906323b872dd90606401600060405180830381600087803b15801561346a57600080fd5b505af115801561347e573d6000803e3d6000fd5b505050505050505050565b60008151600381111561349e5761349e61471c565b036134ac576134ac81613bf2565b6001600160a01b0383166000908152600f60209081526040808320858452909152812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168155600181018290556002810180547fffffffffffffffffffffffff0000000000000000000000000000000000000000908116909155600382018054821690556004820180548216905560058201839055600682018390556007820180549091169055600881018290556009810182905590613572600a8301826143f4565b50506135ab6040805160808101825260008082526020808301829052828401829052835180850190945281845283015290606082015290565b600285600a8111156135bf576135bf61471c565b14806135dc5750600485600a8111156135da576135da61471c565b145b806135f85750600985600a8111156135f6576135f661471c565b145b15613619576136168260600151836020015184604001518787613d91565b90505b7f6394c5b8350821907b88cf72ed5740bb13cc27d962a0868c3efe34a9a8045f198585858585604051613650959493929190614d3c565b60405180910390a15050505050565b610100810151156133a6576101008101805160009182905260e08301516001600160a01b039081168352600e6020908152604080852081870151909316855291905282208054919283926136b4908490614db9565b90915550505050565b6136c68161413e565b6040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018890526001600160a01b038916906323b872dd90606401600060405180830381600087803b15801561372d57600080fd5b505af1158015613741573d6000803e3d6000fd5b5050505060006040518061016001604052808660038111156137655761376561471c565b815260208082018a90526001600160a01b03808a166040808501919091523360608501526000608085018190524260a086015260c0850189905260e08501819052610100850181905260016101208601819052610140909501889052918e168252600f83528082208d8352909252208251815493945084939192909183917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00919091169083600381111561381b5761381b61471c565b0217905550602082810151600183015560408301516002830180546001600160a01b039283167fffffffffffffffffffffffff0000000000000000000000000000000000000000918216179091556060850151600385018054918416918316919091179055608085015160048501805491841691831691909117905560a0850151600585015560c0850151600685015560e08501516007850180549190931691161790556101008301516008830155610120830151600983015561014083015180516138ed92600a8501920190614412565b509050507f6394c5b8350821907b88cf72ed5740bb13cc27d962a0868c3efe34a9a8045f19848a8a846040518060800160405280600081526020018c6001600160a01b0316815260200160008152602001604051806040016040528060006001600160a01b031681526020016000815250815250604051613972959493929190614d3c565b60405180910390a1505050505050505050565b6040516001600160a01b03808516602483015283166044820152606481018290526139d69085907f23b872dd00000000000000000000000000000000000000000000000000000000906084016132b7565b50505050565b6001600160a01b0382166000908152600f60209081526040808320848452909152808220815161016081019092528054829060ff166003811115613a2257613a2261471c565b6003811115613a3357613a3361471c565b8152600182015460208083019190915260028301546001600160a01b03908116604080850191909152600385015482166060850152600485015482166080850152600585015460a0850152600685015460c0850152600785015490911660e084015260088401546101008401526009840154610120840152600a84018054825181850281018501909352808352610140909401939192909190830182828015613b0557602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613ae7575b5050509190925250505060608101519091506001600160a01b0316613b6c5760405162461bcd60e51b815260206004820152601060248201527f4974656d206e6f74206f6e2073616c6500000000000000000000000000000000604482015260640161088a565b600081516003811115613b8157613b8161471c565b14613bce5760405162461bcd60e51b815260206004820152600e60248201527f496e636f72726563742074797065000000000000000000000000000000000000604482015260640161088a565b3360808201819052613be5908490849030906133fc565b6109a56002848484613489565b61014081015151156133a6576000805b82610140015151811015613c5e57336001600160a01b03168361014001518281518110613c3157613c31614b62565b60200260200101516001600160a01b031603613c4c57600191505b80613c5681614bc0565b915050613c02565b50806109605760405162461bcd60e51b815260206004820152601c60248201527f4e6f7420616c6c6f77656420696e20707269766174652073616c652e00000000604482015260640161088a565b6000613d01826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166141919092919063ffffffff16565b8051909150156109a55780806020019051810190613d1f9190614e24565b6109a55760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161088a565b613dc86040805160808101825260008082526020808301829052828401829052835180850190945281845283015290606082015290565b600d546000906001600160a01b0390811690861603613e0357612710600a5487613df29190614dd2565b613dfc9190614de9565b9050613e21565b61271060095487613e149190614dd2565b613e1e9190614de9565b90505b600080613e2d866141a8565b15613f1b576040517f2a55205a00000000000000000000000000000000000000000000000000000000815260048101869052602481018990526001600160a01b03871690632a55205a906044016040805180830381865afa158015613e96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613eba9190614e46565b92509050613ec88389614e74565b8210613f165760405162461bcd60e51b815260206004820152601060248201527f526f79616c747920746f6f206869676800000000000000000000000000000000604482015260640161088a565b613f70565b6001600160a01b03861660009081526002602052604090206001015461271090613f45908a614dd2565b613f4f9190614de9565b6001600160a01b038088166000908152600260205260409020549193501690505b600082613f7d858b614e74565b613f879190614e74565b6001600160a01b03808c166000908152600e60209081526040808320938d16835292905290812080549293508392909190613fc3908490614db9565b9091555050821561400b576001600160a01b038083166000908152600e60209081526040808320938c1683529290529081208054859290614005908490614db9565b90915550505b6001600160a01b0388166140c257600b546040516000916001600160a01b03169086908381818185875af1925050503d8060008114614066576040519150601f19603f3d011682016040523d82523d6000602084013e61406b565b606091505b50509050806140bc5760405162461bcd60e51b815260206004820152600f60248201527f5472616e73666572206661696c65640000000000000000000000000000000000604482015260640161088a565b506140dc565b600b546140dc906001600160a01b038a8116911686613272565b604080516080810182529182526001600160a01b03988916602080840191909152828201959095529688166000908152600285528790208751808901909852805490981687526001909701549286019290925250505050606082015292915050565b600354815111156133a65760405162461bcd60e51b815260206004820152601a60248201527f507269766174652073616c65206c69737420746f6f206c6f6e67000000000000604482015260640161088a565b60606141a08484600085614264565b949350505050565b6040517f2a55205a00000000000000000000000000000000000000000000000000000000815260006004820181905260248201819052906001600160a01b03831690632a55205a906044016040805180830381865afa925050508015614249575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261424691810190614e46565b60015b61425557506000919050565b5060019392505050565b919050565b6060824710156142dc5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c0000000000000000000000000000000000000000000000000000606482015260840161088a565b600080866001600160a01b031685876040516142f89190614eab565b60006040518083038185875af1925050503d8060008114614335576040519150601f19603f3d011682016040523d82523d6000602084013e61433a565b606091505b509150915061434b87838387614356565b979650505050505050565b606083156143c55782516000036143be576001600160a01b0385163b6143be5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161088a565b50816141a0565b6141a083838151156143da5781518083602001fd5b8060405162461bcd60e51b815260040161088a9190614ec7565b50805460008255906000526020600020908101906133a6919061448f565b82805482825590600052602060002090810192821561447f579160200282015b8281111561447f57825182547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03909116178255602090920191600190910190614432565b5061448b92915061448f565b5090565b5b8082111561448b5760008155600101614490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561451a5761451a6144a4565b604052919050565b600067ffffffffffffffff82111561453c5761453c6144a4565b5060051b60200190565b6001600160a01b03811681146133a657600080fd5b803561425f81614546565b600082601f83011261457757600080fd5b8135602061458c61458783614522565b6144d3565b82815260059290921b840181019181810190868411156145ab57600080fd5b8286015b848110156145cf5780356145c281614546565b83529183019183016145af565b509695505050505050565b600080604083850312156145ed57600080fd5b823567ffffffffffffffff81111561460457600080fd5b61461085828601614566565b925050602083013561462181614546565b809150509250929050565b600082601f83011261463d57600080fd5b8135602061464d61458783614522565b82815260059290921b8401810191818101908684111561466c57600080fd5b8286015b848110156145cf5780358352918301918301614670565b6000806040838503121561469a57600080fd5b82356146a581614546565b9150602083013567ffffffffffffffff8111156146c157600080fd5b6146cd8582860161462c565b9150509250929050565b6000602082840312156146e957600080fd5b5035919050565b6000806040838503121561470357600080fd5b823561470e81614546565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6004811061475b5761475b61471c565b9052565b610140810161476e828d61474b565b602082019a909a526001600160a01b0398891660408201529688166060880152948716608087015260a086019390935260c085019190915290931660e08301526101008201929092526101200152919050565b6000806000606084860312156147d657600080fd5b83356147e181614546565b92506020840135915060408401356147f881614546565b809150509250925092565b60008083601f84011261481557600080fd5b50813567ffffffffffffffff81111561482d57600080fd5b6020830191508360208260051b850101111561484857600080fd5b9250929050565b60008060008060008060a0878903121561486857600080fd5b863561487381614546565b9550602087013567ffffffffffffffff8082111561489057600080fd5b61489c8a838b0161462c565b965060408901359150808211156148b257600080fd5b6148be8a838b0161462c565b955060608901359150808211156148d457600080fd5b6148e08a838b01614566565b945060808901359150808211156148f657600080fd5b5061490389828a01614803565b979a9699509497509295939492505050565b60008060008060008060a0878903121561492e57600080fd5b863561493981614546565b95506020870135945060408701359350606087013561495781614546565b9250608087013567ffffffffffffffff81111561497357600080fd5b61490389828a01614803565b60006020828403121561499157600080fd5b813561499c81614546565b9392505050565b600080600080600080600060c0888a0312156149be57600080fd5b6149c78861455b565b9650602088013567ffffffffffffffff808211156149e457600080fd5b6149f08b838c0161462c565b975060408a0135915080821115614a0657600080fd5b614a128b838c0161462c565b965060608a0135915080821115614a2857600080fd5b614a348b838c01614566565b955060808a0135915080821115614a4a57600080fd5b614a568b838c0161462c565b945060a08a0135915080821115614a6c57600080fd5b50614a798a828b01614803565b989b979a50959850939692959293505050565b600080600080600080600060c0888a031215614aa757600080fd5b8735614ab281614546565b965060208801359550604088013594506060880135614ad081614546565b93506080880135925060a088013567ffffffffffffffff811115614af357600080fd5b614a798a828b01614803565b60008060408385031215614b1257600080fd5b8235614b1d81614546565b9150602083013561462181614546565b600080600060608486031215614b4257600080fd5b8335614b4d81614546565b95602085013595506040909401359392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614bf157614bf1614b91565b5060010190565b600060208284031215614c0a57600080fd5b815161499c81614546565b600b811061475b5761475b61471c565b600081518084526020808501945080840160005b83811015614c5e5781516001600160a01b031687529582019590820190600101614c39565b509495945050505050565b6000610160614c7984845161474b565b602083015160208501526040830151614c9d60408601826001600160a01b03169052565b506060830151614cb860608601826001600160a01b03169052565b506080830151614cd360808601826001600160a01b03169052565b5060a083015160a085015260c083015160c085015260e0830151614d0260e08601826001600160a01b03169052565b506101008381015190850152610120808401519085015261014080840151818601839052614d3283870182614c25565b9695505050505050565b6000610120614d4b8389614c15565b6001600160a01b0387166020840152856040840152806060840152614d7281840186614c69565b845160808501526020808601516001600160a01b0390811660a0870152604087015160c08701526060870151805190911660e087015201516101008501529150614d329050565b80820180821115614dcc57614dcc614b91565b92915050565b8082028115828204841417614dcc57614dcc614b91565b600082614e1f577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b600060208284031215614e3657600080fd5b8151801515811461499c57600080fd5b60008060408385031215614e5957600080fd5b8251614e6481614546565b6020939093015192949293505050565b81810381811115614dcc57614dcc614b91565b60005b83811015614ea2578181015183820152602001614e8a565b50506000910152565b60008251614ebd818460208701614e87565b9190910192915050565b6020815260008251806020840152614ee6816040850160208701614e87565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea264697066735822122050c680a6ffdee7aff64b42dcc533e49fbeb214722dcefca55f2dca78569d157764736f6c63430008110033000000000000000000000000476559a5665f8f42402e42b04b0a4cfd6769b7b8000000000000000000000000d032365c138e7385bc50f6df12fe5ef8eca8f0ec000000000000000000000000207e6b4529840a4fd518f73c68bc9c19b2a15944

Deployed ByteCode

0x6080604052600436106101fe5760003560e01c80639fa6b4a01161011d578063cac025c4116100b0578063ea7a25171161007f578063f9af8b3811610064578063f9af8b381461066c578063f9eaee0d1461068c578063fba133d9146106d457600080fd5b8063ea7a25171461061f578063ee8d4b8e1461064c57600080fd5b8063cac025c414610591578063e1671a0d146105a7578063e6115c64146105c7578063e831be58146105e757600080fd5b8063b1b9e78d116100ec578063b1b9e78d14610528578063b2a4706e14610548578063b5fc53121461055b578063c18aca341461057b57600080fd5b80639fa6b4a014610480578063a0b335e3146104df578063a5ec9c1b146104f5578063aabbbd651461050857600080fd5b8063770915e111610195578063897a849b11610164578063897a849b14610414578063947234951461042a578063978c0bef1461044a5780639e9057951461046a57600080fd5b8063770915e11461037c5780637e3647a9146103b457806381874e51146103d457806388cedbc4146103f457600080fd5b8063460a38cb116101d1578063460a38cb146102845780635c80a435146102a457806364e11d7414610346578063737ab3e31461036657600080fd5b80630556f4f3146102035780630e519ef91461022c578063157620ab1461024257806337d92e7a14610264575b600080fd5b34801561020f57600080fd5b5061021960095481565b6040519081526020015b60405180910390f35b34801561023857600080fd5b5061021960085481565b34801561024e57600080fd5b5061026261025d3660046145da565b6106e7565b005b34801561027057600080fd5b5061026261027f366004614687565b610964565b34801561029057600080fd5b5061026261029f3660046146d7565b6109aa565b3480156102b057600080fd5b506103306102bf3660046146f0565b600f602090815260009283526040808420909152908252902080546001820154600283015460038401546004850154600586015460068701546007880154600889015460099099015460ff9098169896976001600160a01b039687169795871696948516959394929391909216918a565b6040516102239a9998979695949392919061475f565b34801561035257600080fd5b506102626103613660046147c1565b610a5b565b34801561037257600080fd5b5061021960045481565b34801561038857600080fd5b50600b5461039c906001600160a01b031681565b6040516001600160a01b039091168152602001610223565b3480156103c057600080fd5b506102626103cf36600461484f565b610d83565b3480156103e057600080fd5b506102626103ef366004614687565b610ea5565b34801561040057600080fd5b5061026261040f3660046146f0565b610ee6565b34801561042057600080fd5b5061021960065481565b34801561043657600080fd5b506102626104453660046146f0565b61119f565b34801561045657600080fd5b50610262610465366004614915565b611583565b34801561047657600080fd5b5061021960055481565b34801561048c57600080fd5b506104c061049b36600461497f565b600260205260009081526040902080546001909101546001600160a01b039091169082565b604080516001600160a01b039093168352602083019190915201610223565b3480156104eb57600080fd5b5061021960075481565b610262610503366004614687565b611861565b34801561051457600080fd5b50600c5461039c906001600160a01b031681565b34801561053457600080fd5b506102626105433660046146f0565b6119fb565b6102626105563660046146f0565b611bd7565b34801561056757600080fd5b50600d5461039c906001600160a01b031681565b34801561058757600080fd5b5061021960035481565b34801561059d57600080fd5b50610219600a5481565b3480156105b357600080fd5b506102626105c23660046149a3565b6120fd565b3480156105d357600080fd5b506102626105e2366004614a8c565b612209565b3480156105f357600080fd5b50610219610602366004614aff565b600e60209081526000928352604080842090915290825290205481565b34801561062b57600080fd5b5061021961063a36600461497f565b60016020526000908152604090205481565b34801561065857600080fd5b506102626106673660046146f0565b61259e565b34801561067857600080fd5b506102626106873660046146f0565b612972565b34801561069857600080fd5b506106c46106a736600461497f565b6001600160a01b0316600090815260016020526040902054151590565b6040519015158152602001610223565b6102626106e2366004614b2d565b612ada565b6106ef613219565b60005b8251811015610955576001600160a01b0382166000908152600e602052604081208451829086908590811061072957610729614b62565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000205490506000811115610942576001600160a01b0383166000908152600e60205260408120855190919086908590811061078c5761078c614b62565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000206000905560006001600160a01b03168483815181106107d5576107d5614b62565b60200260200101516001600160a01b031603610899576000836001600160a01b03168260405160006040518083038185875af1925050503d8060008114610838576040519150601f19603f3d011682016040523d82523d6000602084013e61083d565b606091505b50509050806108935760405162461bcd60e51b815260206004820152601060248201527f5472616e73666572206661696c65642e0000000000000000000000000000000060448201526064015b60405180910390fd5b506108d0565b6108d083828685815181106108b0576108b0614b62565b60200260200101516001600160a01b03166132729092919063ffffffff16565b7e1a143d5b175701cb3246058ffac3d63945192075a926ff73a19930f09d587a838286858151811061090457610904614b62565b6020026020010151604051610939939291906001600160a01b0393841681526020810192909252909116604082015260600190565b60405180910390a15b508061094d81614bc0565b9150506106f2565b506109606001600055565b5050565b60005b81518110156109a5576109938383838151811061098657610986614b62565b6020026020010151610ee6565b8061099d81614bc0565b915050610967565b505050565b600c546001600160a01b03163314610a045760405162461bcd60e51b815260206004820152600a60248201527f4e6f742057697a61726400000000000000000000000000000000000000000000604482015260640161088a565b610171811115610a565760405162461bcd60e51b815260206004820152601060248201527f466565206e6f7420696e2072616e676500000000000000000000000000000000604482015260640161088a565b600955565b610a63613219565b600454821115610ab55760405162461bcd60e51b815260206004820152601f60248201527f526f79616c746965732063616e6e6f7420657863656564206d6178696d756d00604482015260640161088a565b6001600160a01b038116610b0b5760405162461bcd60e51b815260206004820152601360248201527f7265636569766572206973206e6f742073657400000000000000000000000000604482015260640161088a565b6001600160a01b038381166000908152600260205260409020541615610b96576001600160a01b038316600090815260026020526040902060010154821115610b965760405162461bcd60e51b815260206004820152601d60248201527f526f79616c746965732063616e6e6f7420626520696e63726561736564000000604482015260640161088a565b336001600160a01b0316836001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bde573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c029190614bf8565b6001600160a01b031614610c585760405162461bcd60e51b815260206004820152600c60248201527f556e617574686f72697a65640000000000000000000000000000000000000000604482015260640161088a565b6040805180820182526001600160a01b038381168252602080830186815287831660009081526002808452868220865181547fffffffffffffffffffffffff000000000000000000000000000000000000000016961695909517855591516001909401939093558451838152610180810186528083019182528086018490526060808201859052608080830186905260a0830186905260c0830186905260e08301869052610100830186905261012083018690526101408301869052610160830183905287519081018852858152938401859052838701859052830185905294519394937f6394c5b8350821907b88cf72ed5740bb13cc27d962a0868c3efe34a9a8045f1993610d6f936007938b93909190614d3c565b60405180910390a150506109a56001600055565b8351855114610dd45760405162461bcd60e51b815260206004820152600f60248201527f4c656e677468206d69736d617463680000000000000000000000000000000000604482015260640161088a565b8251845114610e255760405162461bcd60e51b815260206004820152600f60248201527f4c656e677468206d69736d617463680000000000000000000000000000000000604482015260640161088a565b60005b8551811015610e9c57610e8a87878381518110610e4757610e47614b62565b6020026020010151878481518110610e6157610e61614b62565b6020026020010151878581518110610e7b57610e7b614b62565b60200260200101518787611583565b80610e9481614bc0565b915050610e28565b50505050505050565b60005b81518110156109a557610ed483838381518110610ec757610ec7614b62565b602002602001015161119f565b80610ede81614bc0565b915050610ea8565b610eee613219565b60016001600160a01b0383166000908152600f6020908152604080832085845290915290205460ff166003811115610f2857610f2861471c565b14610f755760405162461bcd60e51b815260206004820152600e60248201527f496e636f72726563742074797065000000000000000000000000000000000000604482015260640161088a565b6001600160a01b0382166000908152600f60209081526040808320848452909152808220815161016081019092528054829060ff166003811115610fbb57610fbb61471c565b6003811115610fcc57610fcc61471c565b8152600182015460208083019190915260028301546001600160a01b03908116604080850191909152600385015482166060850152600485015482166080850152600585015460a0850152600685015460c0850152600785015490911660e084015260088401546101008401526009840154610120840152600a8401805482518185028101850190935280835261014090940193919290919083018282801561109e57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611080575b505050919092525050506101008101519091506110ba82613339565b83600460008390036111565760608401516040517f23b872dd0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b03918216602482015260448101879052908316906323b872dd90606401600060405180830381600087803b15801561113557600080fd5b505af1158015611149573d6000803e3d6000fd5b505050506005905061117a565b60e08401516001600160a01b03166080850181905261117a908790879030906133fc565b610100840151602085015261119181878787613489565b505050506109606001600055565b6111a7613219565b6001600160a01b0382166000908152600f60209081526040808320848452909152808220815161016081019092528054829060ff1660038111156111ed576111ed61471c565b60038111156111fe576111fe61471c565b8152600182015460208083019190915260028301546001600160a01b03908116604080850191909152600385015482166060850152600485015482166080850152600585015460a0850152600685015460c0850152600785015490911660e084015260088401546101008401526009840154610120840152600a840180548251818502810185019093528083526101409094019391929091908301828280156112d057602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116112b2575b5050505050815250509050336001600160a01b031681606001516001600160a01b0316146113405760405162461bcd60e51b815260206004820152601160248201527f4e6f74206f776e6572206f66206974656d000000000000000000000000000000604482015260640161088a565b6005548160a001516113529190614db9565b42116113a05760405162461bcd60e51b815260206004820152601360248201527f546f6f206561726c7920746f2063616e63656c00000000000000000000000000604482015260640161088a565b6040517f23b872dd0000000000000000000000000000000000000000000000000000000081523060048201523360248201526044810183905283906001600160a01b038216906323b872dd90606401600060405180830381600087803b15801561140957600080fd5b505af115801561141d573d6000803e3d6000fd5b5050506001600160a01b0385166000908152600f60209081526040808320878452909152812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168155600181018290556002810180547fffffffffffffffffffffffff0000000000000000000000000000000000000000908116909155600382018054821690556004820180548216905560058201839055600682018390556007820180549091169055600881018290556009810182905591506114e7600a8301826143f4565b50507f6394c5b8350821907b88cf72ed5740bb13cc27d962a0868c3efe34a9a8045f19600185858560405180608001604052806000815260200188604001516001600160a01b0316815260200160008152602001604051806040016040528060006001600160a01b03168152602001600081525081525060405161156f959493929190614d3c565b60405180910390a150506109606001600055565b61158b613219565b6001600160a01b038316600090815260016020526040902054806115f15760405162461bcd60e51b815260206004820152601260248201527f666c6f6f72507269636520696e76616c69640000000000000000000000000000604482015260640161088a565b808510156116415760405162461bcd60e51b815260206004820152601260248201527f666c6f6f725072696365206e6f74206d65740000000000000000000000000000604482015260640161088a565b6001600160a01b0387166000908152600f60209081526040808320898452909152808220815161016081019092528054829060ff1660038111156116875761168761471c565b60038111156116985761169861471c565b8152600182015460208083019190915260028301546001600160a01b03908116604080850191909152600385015482166060850152600485015482166080850152600585015460a0850152600685015460c0850152600785015490911660e084015260088401546101008401526009840154610120840152600a8401805482518185028101850190935280835261014090940193919290919083018282801561176a57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161174c575b50505050508152505090506003808111156117875761178761471c565b8151600381111561179a5761179a61471c565b036117ad576117a88161365f565b611808565b60608101516001600160a01b0316156118085760405162461bcd60e51b815260206004820152600b60248201527f4974656d206c6973746564000000000000000000000000000000000000000000604482015260640161088a565b61184d8888888860008060008b8b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506136bd92505050565b50506118596001600055565b505050505050565b611869613219565b6000805b82518110156119a2576001600160a01b0384166000908152600f60205260408120845182908690859081106118a4576118a4614b62565b6020026020010151815260200190815260200160002060020160009054906101000a90046001600160a01b031690506000600f6000876001600160a01b03166001600160a01b03168152602001908152602001600020600086858151811061190e5761190e614b62565b6020026020010151815260200190815260200160002060010154905060006001600160a01b0316826001600160a01b0316036119555761194e8185614db9565b935061196a565b61196a6001600160a01b038316333084613985565b61198d8686858151811061198057611980614b62565b60200260200101516139dc565b5050808061199a90614bc0565b91505061186d565b508015806119af57508034145b6109555760405162461bcd60e51b815260206004820152600960248201527f496e636f72726563740000000000000000000000000000000000000000000000604482015260640161088a565b611a03613219565b6001600160a01b0382166000908152600f60209081526040808320848452909152808220815161016081019092528054829060ff166003811115611a4957611a4961471c565b6003811115611a5a57611a5a61471c565b8152600182015460208083019190915260028301546001600160a01b03908116604080850191909152600385015482166060850152600485015482166080850152600585015460a0850152600685015460c0850152600785015490911660e084015260088401546101008401526009840154610120840152600a84018054825181850281018501909352808352610140909401939192909190830182828015611b2c57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611b0e575b5050505050815250509050600380811115611b4957611b4961471c565b81516003811115611b5c57611b5c61471c565b14611ba95760405162461bcd60e51b815260206004820152601260248201527f4e6f206f6666657220617661696c61626c650000000000000000000000000000604482015260640161088a565b611bb983833384608001516133fc565b61010081015160208201523360608201526109556009848484613489565b611bdf613219565b6001600160a01b0382166000908152600f60209081526040808320848452909152808220815161016081019092528054829060ff166003811115611c2557611c2561471c565b6003811115611c3657611c3661471c565b8152600182015460208083019190915260028301546001600160a01b03908116604080850191909152600385015482166060850152600485015482166080850152600585015460a0850152600685015460c0850152600785015490911660e084015260088401546101008401526009840154610120840152600a84018054825181850281018501909352808352610140909401939192909190830182828015611d0857602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611cea575b5050505050815250509050600380811115611d2557611d2561471c565b81516003811115611d3857611d3861471c565b1480611d4f575060608101516001600160a01b0316155b611d9b5760405162461bcd60e51b815260206004820152601360248201527f4974656d20616c7265616479206c697374656400000000000000000000000000604482015260640161088a565b6040517f6352211e000000000000000000000000000000000000000000000000000000008152600481018390526000906001600160a01b03851690636352211e90602401602060405180830381865afa158015611dfc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e209190614bf8565b9050336001600160a01b03821603611e7a5760405162461bcd60e51b815260206004820152600e60248201527f4974656d206e6f74206f776e6564000000000000000000000000000000000000604482015260640161088a565b670de0b6b3a76400003410158015611ec057506064600654836101000151611ea29190614dd2565b611eac9190614de9565b826101000151611ebc9190614db9565b3410155b611f0c5760405162461bcd60e51b815260206004820152601960248201527f496e73756666696369656e74206f6666657220616d6f756e7400000000000000604482015260640161088a565b611f158261365f565b6003808352346101008401523360e084018190526001600160a01b03838116606086015260808501919091524260a085015285166000908152600f60209081526040808320878452909152902083518154859383917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016906001908490811115611fa157611fa161471c565b0217905550602082810151600183015560408301516002830180546001600160a01b039283167fffffffffffffffffffffffff0000000000000000000000000000000000000000918216179091556060850151600385018054918416918316919091179055608085015160048501805491841691831691909117905560a0850151600585015560c0850151600685015560e085015160078501805491909316911617905561010083015160088301556101208301516009830155610140830151805161207392600a8501920190614412565b509050507f6394c5b8350821907b88cf72ed5740bb13cc27d962a0868c3efe34a9a8045f19600885858560405180608001604052806000815260200188604001516001600160a01b0316815260200160008152602001604051806040016040528060006001600160a01b03168152602001600081525081525060405161156f959493929190614d3c565b8451865114801561210f575083518651145b801561211c575082518651145b6121685760405162461bcd60e51b815260206004820152600f60248201527f4c656e677468206d69736d617463680000000000000000000000000000000000604482015260640161088a565b60005b86518110156121ff57600085828151811061218857612188614b62565b602002602001015190506121ec898984815181106121a8576121a8614b62565b60200260200101518985815181106121c2576121c2614b62565b6020026020010151848987815181106121dd576121dd614b62565b60200260200101518989612209565b50806121f781614bc0565b91505061216b565b5050505050505050565b612211613219565b6001600160a01b0384166000908152600160205260409020548590849086908061227d5760405162461bcd60e51b815260206004820152601560248201527f496e76616c696420746f6b656e20616464726573730000000000000000000000604482015260640161088a565b808410156122cd5760405162461bcd60e51b815260206004820152601160248201527f4d696e207072696365206e6f74206d6574000000000000000000000000000000604482015260640161088a565b6007546122da9042614db9565b83116123285760405162461bcd60e51b815260206004820152601a60248201527f41756374696f6e206d696e206c656e677468206e6f74206d6574000000000000604482015260640161088a565b6008546123359042614db9565b83106123835760405162461bcd60e51b815260206004820152601a60248201527f41756374696f6e206d6178206c656e677468206e6f74206d6574000000000000604482015260640161088a565b6001600160a01b038b166000908152600f602090815260408083208d8452909152808220815161016081019092528054829060ff1660038111156123c9576123c961471c565b60038111156123da576123da61471c565b8152600182015460208083019190915260028301546001600160a01b03908116604080850191909152600385015482166060850152600485015482166080850152600585015460a0850152600685015460c0850152600785015490911660e084015260088401546101008401526009840154610120840152600a840180548251818502810185019093528083526101409094019391929091908301828280156124ac57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161248e575b50505050508152505090506003808111156124c9576124c961471c565b815160038111156124dc576124dc61471c565b036124ef576124ea8161365f565b61254a565b60608101516001600160a01b03161561254a5760405162461bcd60e51b815260206004820152601360248201527f4974656d20616c7265616479206c697374656400000000000000000000000000604482015260640161088a565b61258f8c8c8c8c600160038e8e8e808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506136bd92505050565b5050505050610e9c6001600055565b6125a6613219565b6001600160a01b0382166000908152600f60209081526040808320848452909152808220815161016081019092528054829060ff1660038111156125ec576125ec61471c565b60038111156125fd576125fd61471c565b8152600182015460208083019190915260028301546001600160a01b03908116604080850191909152600385015482166060850152600485015482166080850152600585015460a0850152600685015460c0850152600785015490911660e084015260088401546101008401526009840154610120840152600a840180548251818502810185019093528083526101409094019391929091908301828280156126cf57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116126b1575b50505050508152505090506003808111156126ec576126ec61471c565b815160038111156126ff576126ff61471c565b1461274c5760405162461bcd60e51b815260206004820152600c60248201527f4e6f7420616e206f666665720000000000000000000000000000000000000000604482015260640161088a565b60808101516001600160a01b031633146127a85760405162461bcd60e51b815260206004820152601260248201527f4e6f206f6666657220746f207265766f6b650000000000000000000000000000604482015260640161088a565b6005548160a001516127ba9190614db9565b42116128085760405162461bcd60e51b815260206004820152601360248201527f546f6f206561726c7920746f2063616e63656c00000000000000000000000000604482015260640161088a565b6001600160a01b0383166000908152600f60209081526040808320858452909152812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168155600181018290556002810180547fffffffffffffffffffffffff00000000000000000000000000000000000000009081169091556003820180548216905560048201805482169055600582018390556006820183905560078201805490911690556008810182905560098101829055906128ce600a8301826143f4565b50506128d98161365f565b7f6394c5b8350821907b88cf72ed5740bb13cc27d962a0868c3efe34a9a8045f19600a84848460405180608001604052806000815260200187604001516001600160a01b0316815260200160008152602001604051806040016040528060006001600160a01b03168152602001600081525081525060405161295f959493929190614d3c565b60405180910390a1506109606001600055565b600c546001600160a01b031633146129cc5760405162461bcd60e51b815260206004820152600a60248201527f4e6f742057697a61726400000000000000000000000000000000000000000000604482015260640161088a565b60008111612a1c5760405162461bcd60e51b815260206004820152601260248201527f466c6f6f7220707269636520746f206c6f770000000000000000000000000000604482015260640161088a565b6001600160a01b03821660009081526001602052604090205415612a825760405162461bcd60e51b815260206004820152601460248201527f546f6b656e20416c726561647920457869737473000000000000000000000000604482015260640161088a565b6001600160a01b038216600081815260016020908152604091829020849055815192835282018390527f5f798757cbe0f16e7270bbb4823573adf7c4ae480b5a6428dd9be62a06048d57910160405180910390a15050565b612ae2613219565b6001600160a01b0383166000908152600f602090815260408083208584529091529081902081516101608101909252805483929190829060ff166003811115612b2d57612b2d61471c565b6003811115612b3e57612b3e61471c565b8152600182015460208083019190915260028301546001600160a01b03908116604080850191909152600385015482166060850152600485015482166080850152600585015460a0850152600685015460c0850152600785015490911660e084015260088401546101008401526009840154610120840152600a84018054825181850281018501909352808352610140909401939192909190830182828015612c1057602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612bf2575b505050919092525060019150612c239050565b81516003811115612c3657612c3661471c565b14612c835760405162461bcd60e51b815260206004820152601360248201527f496e636f72726563742073616c65207479706500000000000000000000000000604482015260640161088a565b60608101516001600160a01b0316612cdd5760405162461bcd60e51b815260206004820152601360248201527f4974656d206973206e6f74206f6e2073616c6500000000000000000000000000604482015260640161088a565b8060c00151600003612d315760405162461bcd60e51b815260206004820152600d60248201527f41756374696f6e20656e64656400000000000000000000000000000000000000604482015260640161088a565b8060c00151421115612d855760405162461bcd60e51b815260206004820152601160248201527f41756374696f6e20636f6d706c65746564000000000000000000000000000000604482015260640161088a565b806101000151600003612deb578060200151821015612de65760405162461bcd60e51b815260206004820152601160248201527f4d696e207072696365206e6f74206d6574000000000000000000000000000000604482015260640161088a565b612e69565b6064600654826101000151612e009190614dd2565b612e0a9190614de9565b816101000151612e1a9190614db9565b821015612e695760405162461bcd60e51b815260206004820152600b60248201527f42696420746f6f206c6f77000000000000000000000000000000000000000000604482015260640161088a565b6001600160a01b0385166000908152600f60209081526040808320878452909152808220815161016081019092528054829060ff166003811115612eaf57612eaf61471c565b6003811115612ec057612ec061471c565b8152600182015460208083019190915260028301546001600160a01b03908116604080850191909152600385015482166060850152600485015482166080850152600585015460a0850152600685015460c0850152600785015490911660e084015260088401546101008401526009840154610120840152600a84018054825181850281018501909352808352610140909401939192909190830182828015612f9257602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612f74575b5050505050815250509050612fa681613bf2565b612faf8161365f565b3360e082015260408101516001600160a01b031661302357346101008201819052841461301e5760405162461bcd60e51b815260206004820152601460248201527f42696420616d6f756e7420696e636f7272656374000000000000000000000000604482015260640161088a565b613045565b61010081018490526040810151613045906001600160a01b0316333087613985565b6001600160a01b0386166000908152600f602090815260408083208884529091529020815181548392919082907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660018360038111156130a8576130a861471c565b0217905550602082810151600183015560408301516002830180546001600160a01b039283167fffffffffffffffffffffffff0000000000000000000000000000000000000000918216179091556060850151600385018054918416918316919091179055608085015160048501805491841691831691909117905560a0850151600585015560c0850151600685015560e085015160078501805491909316911617905561010083015160088301556101208301516009830155610140830151805161317a92600a8501920190614412565b509050507f6394c5b8350821907b88cf72ed5740bb13cc27d962a0868c3efe34a9a8045f19600687878460405180608001604052806000815260200187604001516001600160a01b0316815260200160008152602001604051806040016040528060006001600160a01b031681526020016000815250815250604051613204959493929190614d3c565b60405180910390a15050506109a56001600055565b60026000540361326b5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161088a565b6002600055565b6040516001600160a01b0383166024820152604481018290526109a59084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152613cac565b8061010001516000036133a957426005548260a001516133599190614db9565b106133a65760405162461bcd60e51b815260206004820152601360248201527f546f6f206561726c7920746f2063616e63656c00000000000000000000000000604482015260640161088a565b50565b8060c0015142116133a65760405162461bcd60e51b815260206004820152601560248201527f41756374696f6e20686173206e6f7420656e6465640000000000000000000000604482015260640161088a565b6040517f23b872dd0000000000000000000000000000000000000000000000000000000081526001600160a01b0383811660048301528281166024830152604482018590528591908216906323b872dd90606401600060405180830381600087803b15801561346a57600080fd5b505af115801561347e573d6000803e3d6000fd5b505050505050505050565b60008151600381111561349e5761349e61471c565b036134ac576134ac81613bf2565b6001600160a01b0383166000908152600f60209081526040808320858452909152812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168155600181018290556002810180547fffffffffffffffffffffffff0000000000000000000000000000000000000000908116909155600382018054821690556004820180548216905560058201839055600682018390556007820180549091169055600881018290556009810182905590613572600a8301826143f4565b50506135ab6040805160808101825260008082526020808301829052828401829052835180850190945281845283015290606082015290565b600285600a8111156135bf576135bf61471c565b14806135dc5750600485600a8111156135da576135da61471c565b145b806135f85750600985600a8111156135f6576135f661471c565b145b15613619576136168260600151836020015184604001518787613d91565b90505b7f6394c5b8350821907b88cf72ed5740bb13cc27d962a0868c3efe34a9a8045f198585858585604051613650959493929190614d3c565b60405180910390a15050505050565b610100810151156133a6576101008101805160009182905260e08301516001600160a01b039081168352600e6020908152604080852081870151909316855291905282208054919283926136b4908490614db9565b90915550505050565b6136c68161413e565b6040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018890526001600160a01b038916906323b872dd90606401600060405180830381600087803b15801561372d57600080fd5b505af1158015613741573d6000803e3d6000fd5b5050505060006040518061016001604052808660038111156137655761376561471c565b815260208082018a90526001600160a01b03808a166040808501919091523360608501526000608085018190524260a086015260c0850189905260e08501819052610100850181905260016101208601819052610140909501889052918e168252600f83528082208d8352909252208251815493945084939192909183917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00919091169083600381111561381b5761381b61471c565b0217905550602082810151600183015560408301516002830180546001600160a01b039283167fffffffffffffffffffffffff0000000000000000000000000000000000000000918216179091556060850151600385018054918416918316919091179055608085015160048501805491841691831691909117905560a0850151600585015560c0850151600685015560e08501516007850180549190931691161790556101008301516008830155610120830151600983015561014083015180516138ed92600a8501920190614412565b509050507f6394c5b8350821907b88cf72ed5740bb13cc27d962a0868c3efe34a9a8045f19848a8a846040518060800160405280600081526020018c6001600160a01b0316815260200160008152602001604051806040016040528060006001600160a01b031681526020016000815250815250604051613972959493929190614d3c565b60405180910390a1505050505050505050565b6040516001600160a01b03808516602483015283166044820152606481018290526139d69085907f23b872dd00000000000000000000000000000000000000000000000000000000906084016132b7565b50505050565b6001600160a01b0382166000908152600f60209081526040808320848452909152808220815161016081019092528054829060ff166003811115613a2257613a2261471c565b6003811115613a3357613a3361471c565b8152600182015460208083019190915260028301546001600160a01b03908116604080850191909152600385015482166060850152600485015482166080850152600585015460a0850152600685015460c0850152600785015490911660e084015260088401546101008401526009840154610120840152600a84018054825181850281018501909352808352610140909401939192909190830182828015613b0557602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613ae7575b5050509190925250505060608101519091506001600160a01b0316613b6c5760405162461bcd60e51b815260206004820152601060248201527f4974656d206e6f74206f6e2073616c6500000000000000000000000000000000604482015260640161088a565b600081516003811115613b8157613b8161471c565b14613bce5760405162461bcd60e51b815260206004820152600e60248201527f496e636f72726563742074797065000000000000000000000000000000000000604482015260640161088a565b3360808201819052613be5908490849030906133fc565b6109a56002848484613489565b61014081015151156133a6576000805b82610140015151811015613c5e57336001600160a01b03168361014001518281518110613c3157613c31614b62565b60200260200101516001600160a01b031603613c4c57600191505b80613c5681614bc0565b915050613c02565b50806109605760405162461bcd60e51b815260206004820152601c60248201527f4e6f7420616c6c6f77656420696e20707269766174652073616c652e00000000604482015260640161088a565b6000613d01826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166141919092919063ffffffff16565b8051909150156109a55780806020019051810190613d1f9190614e24565b6109a55760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161088a565b613dc86040805160808101825260008082526020808301829052828401829052835180850190945281845283015290606082015290565b600d546000906001600160a01b0390811690861603613e0357612710600a5487613df29190614dd2565b613dfc9190614de9565b9050613e21565b61271060095487613e149190614dd2565b613e1e9190614de9565b90505b600080613e2d866141a8565b15613f1b576040517f2a55205a00000000000000000000000000000000000000000000000000000000815260048101869052602481018990526001600160a01b03871690632a55205a906044016040805180830381865afa158015613e96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613eba9190614e46565b92509050613ec88389614e74565b8210613f165760405162461bcd60e51b815260206004820152601060248201527f526f79616c747920746f6f206869676800000000000000000000000000000000604482015260640161088a565b613f70565b6001600160a01b03861660009081526002602052604090206001015461271090613f45908a614dd2565b613f4f9190614de9565b6001600160a01b038088166000908152600260205260409020549193501690505b600082613f7d858b614e74565b613f879190614e74565b6001600160a01b03808c166000908152600e60209081526040808320938d16835292905290812080549293508392909190613fc3908490614db9565b9091555050821561400b576001600160a01b038083166000908152600e60209081526040808320938c1683529290529081208054859290614005908490614db9565b90915550505b6001600160a01b0388166140c257600b546040516000916001600160a01b03169086908381818185875af1925050503d8060008114614066576040519150601f19603f3d011682016040523d82523d6000602084013e61406b565b606091505b50509050806140bc5760405162461bcd60e51b815260206004820152600f60248201527f5472616e73666572206661696c65640000000000000000000000000000000000604482015260640161088a565b506140dc565b600b546140dc906001600160a01b038a8116911686613272565b604080516080810182529182526001600160a01b03988916602080840191909152828201959095529688166000908152600285528790208751808901909852805490981687526001909701549286019290925250505050606082015292915050565b600354815111156133a65760405162461bcd60e51b815260206004820152601a60248201527f507269766174652073616c65206c69737420746f6f206c6f6e67000000000000604482015260640161088a565b60606141a08484600085614264565b949350505050565b6040517f2a55205a00000000000000000000000000000000000000000000000000000000815260006004820181905260248201819052906001600160a01b03831690632a55205a906044016040805180830381865afa925050508015614249575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261424691810190614e46565b60015b61425557506000919050565b5060019392505050565b919050565b6060824710156142dc5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c0000000000000000000000000000000000000000000000000000606482015260840161088a565b600080866001600160a01b031685876040516142f89190614eab565b60006040518083038185875af1925050503d8060008114614335576040519150601f19603f3d011682016040523d82523d6000602084013e61433a565b606091505b509150915061434b87838387614356565b979650505050505050565b606083156143c55782516000036143be576001600160a01b0385163b6143be5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161088a565b50816141a0565b6141a083838151156143da5781518083602001fd5b8060405162461bcd60e51b815260040161088a9190614ec7565b50805460008255906000526020600020908101906133a6919061448f565b82805482825590600052602060002090810192821561447f579160200282015b8281111561447f57825182547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03909116178255602090920191600190910190614432565b5061448b92915061448f565b5090565b5b8082111561448b5760008155600101614490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561451a5761451a6144a4565b604052919050565b600067ffffffffffffffff82111561453c5761453c6144a4565b5060051b60200190565b6001600160a01b03811681146133a657600080fd5b803561425f81614546565b600082601f83011261457757600080fd5b8135602061458c61458783614522565b6144d3565b82815260059290921b840181019181810190868411156145ab57600080fd5b8286015b848110156145cf5780356145c281614546565b83529183019183016145af565b509695505050505050565b600080604083850312156145ed57600080fd5b823567ffffffffffffffff81111561460457600080fd5b61461085828601614566565b925050602083013561462181614546565b809150509250929050565b600082601f83011261463d57600080fd5b8135602061464d61458783614522565b82815260059290921b8401810191818101908684111561466c57600080fd5b8286015b848110156145cf5780358352918301918301614670565b6000806040838503121561469a57600080fd5b82356146a581614546565b9150602083013567ffffffffffffffff8111156146c157600080fd5b6146cd8582860161462c565b9150509250929050565b6000602082840312156146e957600080fd5b5035919050565b6000806040838503121561470357600080fd5b823561470e81614546565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6004811061475b5761475b61471c565b9052565b610140810161476e828d61474b565b602082019a909a526001600160a01b0398891660408201529688166060880152948716608087015260a086019390935260c085019190915290931660e08301526101008201929092526101200152919050565b6000806000606084860312156147d657600080fd5b83356147e181614546565b92506020840135915060408401356147f881614546565b809150509250925092565b60008083601f84011261481557600080fd5b50813567ffffffffffffffff81111561482d57600080fd5b6020830191508360208260051b850101111561484857600080fd5b9250929050565b60008060008060008060a0878903121561486857600080fd5b863561487381614546565b9550602087013567ffffffffffffffff8082111561489057600080fd5b61489c8a838b0161462c565b965060408901359150808211156148b257600080fd5b6148be8a838b0161462c565b955060608901359150808211156148d457600080fd5b6148e08a838b01614566565b945060808901359150808211156148f657600080fd5b5061490389828a01614803565b979a9699509497509295939492505050565b60008060008060008060a0878903121561492e57600080fd5b863561493981614546565b95506020870135945060408701359350606087013561495781614546565b9250608087013567ffffffffffffffff81111561497357600080fd5b61490389828a01614803565b60006020828403121561499157600080fd5b813561499c81614546565b9392505050565b600080600080600080600060c0888a0312156149be57600080fd5b6149c78861455b565b9650602088013567ffffffffffffffff808211156149e457600080fd5b6149f08b838c0161462c565b975060408a0135915080821115614a0657600080fd5b614a128b838c0161462c565b965060608a0135915080821115614a2857600080fd5b614a348b838c01614566565b955060808a0135915080821115614a4a57600080fd5b614a568b838c0161462c565b945060a08a0135915080821115614a6c57600080fd5b50614a798a828b01614803565b989b979a50959850939692959293505050565b600080600080600080600060c0888a031215614aa757600080fd5b8735614ab281614546565b965060208801359550604088013594506060880135614ad081614546565b93506080880135925060a088013567ffffffffffffffff811115614af357600080fd5b614a798a828b01614803565b60008060408385031215614b1257600080fd5b8235614b1d81614546565b9150602083013561462181614546565b600080600060608486031215614b4257600080fd5b8335614b4d81614546565b95602085013595506040909401359392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614bf157614bf1614b91565b5060010190565b600060208284031215614c0a57600080fd5b815161499c81614546565b600b811061475b5761475b61471c565b600081518084526020808501945080840160005b83811015614c5e5781516001600160a01b031687529582019590820190600101614c39565b509495945050505050565b6000610160614c7984845161474b565b602083015160208501526040830151614c9d60408601826001600160a01b03169052565b506060830151614cb860608601826001600160a01b03169052565b506080830151614cd360808601826001600160a01b03169052565b5060a083015160a085015260c083015160c085015260e0830151614d0260e08601826001600160a01b03169052565b506101008381015190850152610120808401519085015261014080840151818601839052614d3283870182614c25565b9695505050505050565b6000610120614d4b8389614c15565b6001600160a01b0387166020840152856040840152806060840152614d7281840186614c69565b845160808501526020808601516001600160a01b0390811660a0870152604087015160c08701526060870151805190911660e087015201516101008501529150614d329050565b80820180821115614dcc57614dcc614b91565b92915050565b8082028115828204841417614dcc57614dcc614b91565b600082614e1f577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b600060208284031215614e3657600080fd5b8151801515811461499c57600080fd5b60008060408385031215614e5957600080fd5b8251614e6481614546565b6020939093015192949293505050565b81810381811115614dcc57614dcc614b91565b60005b83811015614ea2578181015183820152602001614e8a565b50506000910152565b60008251614ebd818460208701614e87565b9190910192915050565b6020815260008251806020840152614ee6816040850160208701614e87565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea264697066735822122050c680a6ffdee7aff64b42dcc533e49fbeb214722dcefca55f2dca78569d157764736f6c63430008110033