Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- NFTMarketplace
- Optimization enabled
- true
- Compiler version
- v0.8.20+commit.a1b79de6
- Optimization runs
- 200
- EVM Version
- paris
- Verified at
- 2025-05-31T18:55:04.651047Z
Constructor Arguments
0x000000000000000000000000ad3e1f40ffe9318cd7b83b42d01a8c72fcbb8ca700000000000000000000000000000000000000000000000000000000000000190000000000000000000000000000000000000000000000000000000000000019
Arg [0] (address) : 0xad3e1f40ffe9318cd7b83b42d01a8c72fcbb8ca7
Arg [1] (uint256) : 25
Arg [2] (uint256) : 25
Contract source code
// File: @openzeppelin/contracts/utils/Context.sol // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } } // File: @openzeppelin/contracts/access/Ownable.sol // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) pragma solidity ^0.8.20; /** * @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. * * The initial owner is set to the address provided by the deployer. 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; /** * @dev The caller account is not authorized to perform an operation. */ error OwnableUnauthorizedAccount(address account); /** * @dev The owner is not a valid owner account. (eg. `address(0)`) */ error OwnableInvalidOwner(address owner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the address provided by the deployer as the initial owner. */ constructor(address initialOwner) { if (initialOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(initialOwner); } /** * @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 { if (owner() != _msgSender()) { revert OwnableUnauthorizedAccount(_msgSender()); } } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling 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 { if (newOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _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.9.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; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return _status == _ENTERED; } } // File: @openzeppelin/contracts/token/ERC20/IERC20.sol // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-20 standard as defined in the ERC. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the value of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the value of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves a `value` amount of tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 value) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the * allowance mechanism. `value` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 value) external returns (bool); } // File: @openzeppelin/contracts/utils/introspection/IERC165.sol // OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[ERC]. * * 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[ERC 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/token/ERC1155/IERC1155.sol // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC1155/IERC1155.sol) pragma solidity ^0.8.20; /** * @dev Required interface of an ERC-1155 compliant contract, as defined in the * https://eips.ethereum.org/EIPS/eip-1155[ERC]. */ interface IERC1155 is IERC165 { /** * @dev Emitted when `value` amount of tokens of type `id` are transferred from `from` to `to` by `operator`. */ event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value); /** * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all * transfers. */ event TransferBatch( address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values ); /** * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to * `approved`. */ event ApprovalForAll(address indexed account, address indexed operator, bool approved); /** * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI. * * If an {URI} event was emitted for `id`, the standard * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value * returned by {IERC1155MetadataURI-uri}. */ event URI(string value, uint256 indexed id); /** * @dev Returns the value of tokens of token type `id` owned by `account`. */ function balanceOf(address account, uint256 id) external view returns (uint256); /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}. * * Requirements: * * - `accounts` and `ids` must have the same length. */ function balanceOfBatch( address[] calldata accounts, uint256[] calldata ids ) external view returns (uint256[] memory); /** * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`, * * Emits an {ApprovalForAll} event. * * Requirements: * * - `operator` cannot be the zero address. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns true if `operator` is approved to transfer ``account``'s tokens. * * See {setApprovalForAll}. */ function isApprovedForAll(address account, address operator) external view returns (bool); /** * @dev Transfers a `value` amount of tokens of type `id` from `from` to `to`. * * WARNING: This function can potentially allow a reentrancy attack when transferring tokens * to an untrusted contract, when invoking {onERC1155Received} on the receiver. * Ensure to follow the checks-effects-interactions pattern and consider employing * reentrancy guards when interacting with untrusted contracts. * * Emits a {TransferSingle} event. * * Requirements: * * - `to` cannot be the zero address. * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}. * - `from` must have a balance of tokens of type `id` of at least `value` amount. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the * acceptance magic value. */ function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes calldata data) external; /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}. * * WARNING: This function can potentially allow a reentrancy attack when transferring tokens * to an untrusted contract, when invoking {onERC1155BatchReceived} on the receiver. * Ensure to follow the checks-effects-interactions pattern and consider employing * reentrancy guards when interacting with untrusted contracts. * * Emits either a {TransferSingle} or a {TransferBatch} event, depending on the length of the array arguments. * * Requirements: * * - `ids` and `values` must have the same length. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the * acceptance magic value. */ function safeBatchTransferFrom( address from, address to, uint256[] calldata ids, uint256[] calldata values, bytes calldata data ) external; } // File: @openzeppelin/contracts/utils/introspection/ERC165.sol // OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/ERC165.sol) pragma solidity ^0.8.20; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { return interfaceId == type(IERC165).interfaceId; } } // File: @openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC1155/IERC1155Receiver.sol) pragma solidity ^0.8.20; /** * @dev Interface that must be implemented by smart contracts in order to receive * ERC-1155 token transfers. */ interface IERC1155Receiver is IERC165 { /** * @dev Handles the receipt of a single ERC-1155 token type. This function is * called at the end of a `safeTransferFrom` after the balance has been updated. * * NOTE: To accept the transfer, this must return * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` * (i.e. 0xf23a6e61, or its own function selector). * * @param operator The address which initiated the transfer (i.e. msg.sender) * @param from The address which previously owned the token * @param id The ID of the token being transferred * @param value The amount of tokens being transferred * @param data Additional data with no specified format * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed */ function onERC1155Received( address operator, address from, uint256 id, uint256 value, bytes calldata data ) external returns (bytes4); /** * @dev Handles the receipt of a multiple ERC-1155 token types. This function * is called at the end of a `safeBatchTransferFrom` after the balances have * been updated. * * NOTE: To accept the transfer(s), this must return * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` * (i.e. 0xbc197c81, or its own function selector). * * @param operator The address which initiated the batch transfer (i.e. msg.sender) * @param from The address which previously owned the token * @param ids An array containing ids of each token being transferred (order and length must match values array) * @param values An array containing amounts of each token being transferred (order and length must match ids array) * @param data Additional data with no specified format * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed */ function onERC1155BatchReceived( address operator, address from, uint256[] calldata ids, uint256[] calldata values, bytes calldata data ) external returns (bytes4); } // File: @openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC1155/utils/ERC1155Holder.sol) pragma solidity ^0.8.20; /** * @dev Simple implementation of `IERC1155Receiver` that will allow a contract to hold ERC-1155 tokens. * * IMPORTANT: When inheriting this contract, you must include a way to use the received tokens, otherwise they will be * stuck. */ abstract contract ERC1155Holder is ERC165, IERC1155Receiver { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { return interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId); } function onERC1155Received( address, address, uint256, uint256, bytes memory ) public virtual override returns (bytes4) { return this.onERC1155Received.selector; } function onERC1155BatchReceived( address, address, uint256[] memory, uint256[] memory, bytes memory ) public virtual override returns (bytes4) { return this.onERC1155BatchReceived.selector; } } // File: @openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol // OpenZeppelin Contracts (last updated v5.3.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.20; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Storage of the initializable contract. * * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions * when using with upgradeable contracts. * * @custom:storage-location erc7201:openzeppelin.storage.Initializable */ struct InitializableStorage { /** * @dev Indicates that the contract has been initialized. */ uint64 _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool _initializing; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00; /** * @dev The contract is already initialized. */ error InvalidInitialization(); /** * @dev The contract is not initializing. */ error NotInitializing(); /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint64 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in * production. * * Emits an {Initialized} event. */ modifier initializer() { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); // Cache values to avoid duplicated sloads bool isTopLevelCall = !$._initializing; uint64 initialized = $._initialized; // Allowed calls: // - initialSetup: the contract is not in the initializing state and no previous version was // initialized // - construction: the contract is initialized at version 1 (no reinitialization) and the // current contract is just being deployed bool initialSetup = initialized == 0 && isTopLevelCall; bool construction = initialized == 1 && address(this).code.length == 0; if (!initialSetup && !construction) { revert InvalidInitialization(); } $._initialized = 1; if (isTopLevelCall) { $._initializing = true; } _; if (isTopLevelCall) { $._initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint64 version) { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing || $._initialized >= version) { revert InvalidInitialization(); } $._initialized = version; $._initializing = true; _; $._initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { _checkInitializing(); _; } /** * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}. */ function _checkInitializing() internal view virtual { if (!_isInitializing()) { revert NotInitializing(); } } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing) { revert InvalidInitialization(); } if ($._initialized != type(uint64).max) { $._initialized = type(uint64).max; emit Initialized(type(uint64).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint64) { return _getInitializableStorage()._initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _getInitializableStorage()._initializing; } /** * @dev Pointer to storage slot. Allows integrators to override it with a custom storage location. * * NOTE: Consider following the ERC-7201 formula to derive storage locations. */ function _initializableStorageSlot() internal pure virtual returns (bytes32) { return INITIALIZABLE_STORAGE; } /** * @dev Returns a pointer to the storage namespace. */ // solhint-disable-next-line var-name-mixedcase function _getInitializableStorage() private pure returns (InitializableStorage storage $) { bytes32 slot = _initializableStorageSlot(); assembly { $.slot := slot } } } // File: @openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } } // File: @openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) pragma solidity ^0.8.20; /** * @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. * * The initial owner is set to the address provided by the deployer. 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 OwnableUpgradeable is Initializable, ContextUpgradeable { /// @custom:storage-location erc7201:openzeppelin.storage.Ownable struct OwnableStorage { address _owner; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300; function _getOwnableStorage() private pure returns (OwnableStorage storage $) { assembly { $.slot := OwnableStorageLocation } } /** * @dev The caller account is not authorized to perform an operation. */ error OwnableUnauthorizedAccount(address account); /** * @dev The owner is not a valid owner account. (eg. `address(0)`) */ error OwnableInvalidOwner(address owner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the address provided by the deployer as the initial owner. */ function __Ownable_init(address initialOwner) internal onlyInitializing { __Ownable_init_unchained(initialOwner); } function __Ownable_init_unchained(address initialOwner) internal onlyInitializing { if (initialOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(initialOwner); } /** * @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) { OwnableStorage storage $ = _getOwnableStorage(); return $._owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { if (owner() != _msgSender()) { revert OwnableUnauthorizedAccount(_msgSender()); } } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling 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 { if (newOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { OwnableStorage storage $ = _getOwnableStorage(); address oldOwner = $._owner; $._owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } } // File: contracts/interfaces/ICollection.sol pragma solidity ^0.8.17; interface ICollection { struct NFTDetails { string name; string description; string uri; uint256 maxSupply; address creator; } event NFTCreated(string name, string description,uint256 indexed tokenId, address indexed creator, uint256 maxSupply); function initialize( string memory name, string memory symbol, address owner, address marketplace, bool isDrop ) external; function createNFT( string memory name, string memory description, string memory _tokenURI, uint256 maxSupply ) external returns (uint256); function nftDetails(uint256 tokenId) external view returns (NFTDetails memory); function getRoyaltyPercentage() external view returns(uint16); } // File: contracts/marketplace/NFTMarketplace.sol pragma solidity ^0.8.17; contract NFTMarketplace is Ownable, ReentrancyGuard, ERC1155Holder { enum ListingType { FIXED_PRICE, AUCTION } enum AuctionStatus { ACTIVE, ENDED, CANCELLED } enum OfferStatus { PENDING, ACCEPTED, REJECTED, CANCELLED } struct Listing { address seller; uint256 price; uint256 quantity; ListingType listingType; uint256 auctionId; // 0 for fixed price listings } struct AuctionDetails { address seller; uint256 startPrice; uint256 currentPrice; uint256 minBidIncrement; uint256 startTime; uint256 endTime; uint256 tokenId; uint256 quantity; address highestBidder; AuctionStatus status; } struct Offer { address buyer; address seller; uint256 price; uint256 quantity; uint256 createTime; OfferStatus status; } struct FilterParams { address collection; uint256 tokenId; address user; uint8 filterType; } struct BatchPurchaseParams { address collection; uint256 tokenId; address seller; uint256 quantity; } uint256 public primaryFee; uint256 public secondaryFee; address public collectionFactory; uint256 public totalCollections; IERC20 public immutable designatedToken; uint256 private _auctionIds; uint256 private _offerIds; uint256 public minAuctionDuration; uint256 public maxAuctionDuration; uint256 public auctionExtensionInterval; mapping(address => mapping(uint256 => mapping(address => Listing))) public listings; mapping(address => bool) public registeredCollections; mapping(uint256 => address) private collectionIndex; mapping(uint256 => AuctionDetails) public auctions; mapping(uint256 => mapping(address => uint256)) public bids; mapping(uint256 => address) public auctionCollections; // Offer mappings mapping(address => mapping(uint256 => mapping(uint256 => Offer))) public offers; // collection => tokenId => offerId => Offer mapping(address => uint256[]) private userOfferIds; // buyer => offerIds mapping(uint256 => address) private offerCollections; // offerId => collection mapping(uint256 => uint256) private offerTokenIds; // offerId => tokenId mapping(address => uint256[]) private sellerReceivedOffers; // seller => offerIds mapping(address => mapping(uint256 => uint256[])) private tokenOffers; // collection => tokenId => offerIds event NFTListed( address indexed collection, uint256 indexed tokenId, address seller, uint256 price, uint256 quantity, ListingType listingType, uint256 auctionId ); event NFTSold(address indexed collection, uint256 indexed tokenId, address seller, address buyer, uint256 price, uint256 quantity); event ListingRemoved(address indexed collection, uint256 indexed tokenId, address seller, string reason); event ListingQuantityUpdated( address indexed collection, uint256 indexed tokenId, address seller, uint256 newQuantity ); event AuctionCreated( uint256 indexed auctionId, address indexed collection, uint256 indexed tokenId, address seller, uint256 startPrice, uint256 minBidIncrement, uint256 startTime, uint256 endTime, uint256 quantity ); event BidPlaced( uint256 indexed auctionId, address indexed bidder, uint256 amount ); event AuctionSettled( uint256 indexed auctionId, address indexed winner, uint256 amount ); event AuctionCancelled(uint256 indexed auctionId); event AuctionExtended(uint256 indexed auctionId, uint256 newEndTime); event FeeUpdated(bool isPrimary, uint256 newFee); event CollectionRegistered(address indexed collection); event AuctionExtensionIntervalUpdated(uint256 newInterval); event OfferCreated( uint256 indexed offerId, address indexed collection, uint256 indexed tokenId, address buyer, address seller, uint256 price, uint256 quantity ); event OfferAccepted(uint256 indexed offerId, address indexed seller); event OfferRejected(uint256 indexed offerId, address indexed seller); event OfferCancelled(uint256 indexed offerId, address indexed buyer); constructor( address _designatedToken, uint256 _primaryFee, uint256 _secondaryFee ) Ownable(msg.sender) { require(_designatedToken != address(0), "Invalid token address"); require(_primaryFee <= 1000, "Primary fee too high"); require(_secondaryFee <= 1000, "Secondary fee too high"); designatedToken = IERC20(_designatedToken); primaryFee = _primaryFee; secondaryFee = _secondaryFee; minAuctionDuration = 1 hours; maxAuctionDuration = 30 days; auctionExtensionInterval = 10 minutes; } function setCollectionFactory(address _factory) external onlyOwner { require(_factory != address(0), "Invalid factory address"); collectionFactory = _factory; } function registerCollection(address collection) external { require(msg.sender == collectionFactory, "Only factory can register"); require(collection != address(0), "Invalid collection address"); require(!registeredCollections[collection], "Already registered"); registeredCollections[collection] = true; collectionIndex[totalCollections] = collection; totalCollections++; emit CollectionRegistered(collection); } function setPrimaryFee(uint256 _fee) external onlyOwner { require(_fee <= 1000, "Fee too high"); primaryFee = _fee; emit FeeUpdated(true, _fee); } function setSecondaryFee(uint256 _fee) external onlyOwner { require(_fee <= 1000, "Fee too high"); secondaryFee = _fee; emit FeeUpdated(false, _fee); } function listNFT( address collection, uint256 tokenId, uint256 price, uint256 quantity ) external nonReentrant { require(registeredCollections[collection], "Collection not registered"); require(price > 0, "Invalid price"); require(quantity > 0, "Invalid quantity"); require( IERC1155(collection).balanceOf(msg.sender, tokenId) >= quantity, "Insufficient balance" ); // Check if NFT is already listed by this seller Listing storage existingListing = listings[collection][tokenId][msg.sender]; require( existingListing.quantity == 0 || (existingListing.listingType == ListingType.AUCTION && auctions[existingListing.auctionId].status != AuctionStatus.ACTIVE), "Already listed" ); listings[collection][tokenId][msg.sender] = Listing({ seller: msg.sender, price: price, quantity: quantity, listingType: ListingType.FIXED_PRICE, auctionId: 0 }); emit NFTListed( collection, tokenId, msg.sender, price, quantity, ListingType.FIXED_PRICE, 0 ); } function removeListing( address collection, uint256 tokenId ) external nonReentrant { Listing storage listing = listings[collection][tokenId][msg.sender]; require(listing.seller == msg.sender && listing.quantity > 0, "No active listing"); if (listing.listingType == ListingType.AUCTION) { AuctionDetails storage auction = auctions[listing.auctionId]; require(auction.status == AuctionStatus.ACTIVE, "Auction not active"); require(auction.highestBidder == address(0), "Bids already placed"); auction.status = AuctionStatus.CANCELLED; IERC1155(collection).safeTransferFrom( address(this), msg.sender, tokenId, listing.quantity, "" ); emit AuctionCancelled(listing.auctionId); } delete listings[collection][tokenId][msg.sender]; emit ListingRemoved(collection, tokenId, msg.sender, "REMOVED_BY_SELLER"); } function buyListedNFT( address collection, uint256 tokenId, address seller, uint256 quantity ) external nonReentrant { require(registeredCollections[collection], "Collection not registered"); Listing storage listing = listings[collection][tokenId][seller]; require(listing.seller == seller && listing.quantity > 0, "Invalid listing"); require(listing.listingType == ListingType.FIXED_PRICE, "Not a fixed price listing"); require(listing.quantity >= quantity, "Insufficient quantity"); ICollection.NFTDetails memory nftDetails = ICollection(collection).nftDetails(tokenId); uint256 fee = secondaryFee; if(nftDetails.creator == seller) { fee = primaryFee; } uint16 royaltyPercentage = ICollection(collection).getRoyaltyPercentage(); uint256 totalPrice = listing.price * quantity; uint256 platformFee = (totalPrice * fee) / 1000; uint256 royaltyFee = (totalPrice * royaltyPercentage) / 1000; uint256 sellerAmount = totalPrice - platformFee - royaltyFee; designatedToken.transferFrom(msg.sender, address(this), platformFee); designatedToken.transferFrom(msg.sender, seller, sellerAmount); if(royaltyFee > 0) { designatedToken.transferFrom(msg.sender, nftDetails.creator, royaltyFee); } IERC1155(collection).safeTransferFrom(seller, msg.sender, tokenId, quantity, ""); listing.quantity -= quantity; if (listing.quantity == 0) { delete listings[collection][tokenId][seller]; emit ListingRemoved(collection, tokenId, seller, "SOLD_OUT"); } emit NFTSold(collection, tokenId, seller, msg.sender, listing.price, quantity); } function getRegisteredCollections(uint256 offset, uint256 limit) public view returns (address[] memory collections) { require(offset <= totalCollections, "Invalid offset"); uint256 size = totalCollections - offset; if (size > limit) { size = limit; } collections = new address[](size); for (uint256 i = 0; i < size; i++) { collections[i] = collectionIndex[offset + i]; } return collections; } function getCollectionsByOwner(address _owner, uint256 offset, uint256 limit) external view returns (address[] memory _collections, uint256 total) { uint256 count = 0; for (uint256 i = 0; i < totalCollections; i++) { address collection = collectionIndex[i]; if (OwnableUpgradeable(collection).owner() == _owner) { count++; } } require(offset <= count, "Invalid offset"); uint256 size = count - offset; if (size > limit) { size = limit; } _collections = new address[](size); uint256 currentIndex = 0; uint256 skipped = 0; for (uint256 i = 0; i < totalCollections && currentIndex < size; i++) { address collection = collectionIndex[i]; if (OwnableUpgradeable(collection).owner() == _owner) { if (skipped < offset) { skipped++; continue; } _collections[currentIndex] = collection; currentIndex++; } } return (_collections, count); } function withdrawFees() external onlyOwner { uint256 balance = designatedToken.balanceOf(address(this)); if (balance > 0) { designatedToken.transfer(owner(), balance); } } function getListing( address collection, uint256 tokenId, address seller ) external view returns (Listing memory) { return listings[collection][tokenId][seller]; } function createAuction( address collection, uint256 tokenId, uint256 quantity, uint256 startPrice, uint256 minBidIncrement, uint256 duration ) external nonReentrant returns (uint256) { _validateAuctionParams( collection, tokenId, quantity, startPrice, minBidIncrement, duration ); _auctionIds++; uint256 auctionId = _auctionIds; _createAuctionListing( collection, tokenId, quantity, startPrice, auctionId ); _setupAuction( auctionId, collection, tokenId, quantity, startPrice, minBidIncrement, duration ); return auctionId; } function _validateAuctionParams( address collection, uint256 tokenId, uint256 quantity, uint256 startPrice, uint256 minBidIncrement, uint256 duration ) internal view { require(registeredCollections[collection], "Collection not registered"); require(quantity > 0, "Invalid quantity"); require(startPrice > 0, "Invalid start price"); require(minBidIncrement > 0, "Invalid min bid increment"); require(duration >= minAuctionDuration && duration <= maxAuctionDuration, "Invalid duration"); require( IERC1155(collection).balanceOf(msg.sender, tokenId) >= quantity, "Insufficient balance" ); require( IERC1155(collection).isApprovedForAll(msg.sender, address(this)), "Not approved" ); Listing storage existingListing = listings[collection][tokenId][msg.sender]; require( existingListing.quantity == 0 || (existingListing.listingType == ListingType.AUCTION && auctions[existingListing.auctionId].status != AuctionStatus.ACTIVE), "Already listed" ); } function _createAuctionListing( address collection, uint256 tokenId, uint256 quantity, uint256 startPrice, uint256 auctionId ) internal { listings[collection][tokenId][msg.sender] = Listing({ seller: msg.sender, price: startPrice, quantity: quantity, listingType: ListingType.AUCTION, auctionId: auctionId }); emit NFTListed( collection, tokenId, msg.sender, startPrice, quantity, ListingType.AUCTION, auctionId ); } function _setupAuction( uint256 auctionId, address collection, uint256 tokenId, uint256 quantity, uint256 startPrice, uint256 minBidIncrement, uint256 duration ) internal { uint256 startTime = block.timestamp; uint256 endTime = startTime + duration; auctions[auctionId] = AuctionDetails({ seller: msg.sender, startPrice: startPrice, currentPrice: startPrice, minBidIncrement: minBidIncrement, startTime: startTime, endTime: endTime, tokenId: tokenId, quantity: quantity, highestBidder: address(0), status: AuctionStatus.ACTIVE }); auctionCollections[auctionId] = collection; IERC1155(collection).safeTransferFrom( msg.sender, address(this), tokenId, quantity, "" ); emit AuctionCreated( auctionId, collection, tokenId, msg.sender, startPrice, minBidIncrement, startTime, endTime, quantity ); } function placeBid(uint256 auctionId, uint256 bidAmount) external nonReentrant { AuctionDetails storage auction = auctions[auctionId]; require(auction.status == AuctionStatus.ACTIVE, "Auction not active"); require(block.timestamp <= auction.endTime, "Auction ended"); require(bidAmount >= auction.currentPrice + auction.minBidIncrement, "Bid too low"); // Check if bid is placed near the end if (auction.endTime - block.timestamp <= auctionExtensionInterval) { auction.endTime = block.timestamp + auctionExtensionInterval; emit AuctionExtended(auctionId, auction.endTime); } address previousBidder = auction.highestBidder; uint256 previousBid = bids[auctionId][previousBidder]; if (previousBidder != address(0)) { designatedToken.transfer(previousBidder, previousBid); } require( designatedToken.transferFrom(msg.sender, address(this), bidAmount), "Transfer failed" ); auction.highestBidder = msg.sender; auction.currentPrice = bidAmount; bids[auctionId][msg.sender] = bidAmount; emit BidPlaced(auctionId, msg.sender, bidAmount); } function settleAuction(uint256 auctionId) external nonReentrant { AuctionDetails storage auction = auctions[auctionId]; require(auction.status == AuctionStatus.ACTIVE, "Auction not active"); require(block.timestamp > auction.endTime, "Auction not ended"); require(auction.highestBidder != address(0), "No bids placed"); auction.status = AuctionStatus.ENDED; address collection = auctionCollections[auctionId]; uint256 finalPrice = auction.currentPrice; ICollection.NFTDetails memory nftDetails = ICollection(collection).nftDetails(auction.tokenId); uint256 fee = secondaryFee; if(nftDetails.creator == auction.seller) { fee = primaryFee; } uint16 royaltyPercentage = ICollection(collection).getRoyaltyPercentage(); // Calculate fees uint256 platformFee = (finalPrice * fee) / 1000; uint256 royaltyFee = (finalPrice * royaltyPercentage) / 1000; uint256 sellerAmount = finalPrice - platformFee - royaltyFee; // Distribute funds designatedToken.transfer(auction.seller, sellerAmount); if(royaltyFee>0) { designatedToken.transfer(nftDetails.creator, royaltyFee); } // Transfer NFT IERC1155(collection).safeTransferFrom( address(this), auction.highestBidder, auction.tokenId, auction.quantity, "" ); // Remove listing address seller = auction.seller; delete listings[collection][auction.tokenId][seller]; emit ListingRemoved(collection, auction.tokenId, seller, "AUCTION_SETTLED"); emit AuctionSettled(auctionId, auction.highestBidder, finalPrice); } function cancelAuction(uint256 auctionId) external nonReentrant { AuctionDetails storage auction = auctions[auctionId]; require(auction.status == AuctionStatus.ACTIVE, "Auction not active"); require(msg.sender == auction.seller, "Not seller"); require(auction.highestBidder == address(0), "Bids already placed"); auction.status = AuctionStatus.CANCELLED; address collection = auctionCollections[auctionId]; IERC1155(collection).safeTransferFrom( address(this), auction.seller, auction.tokenId, auction.quantity, "" ); // Remove listing delete listings[collection][auction.tokenId][auction.seller]; emit ListingRemoved(collection, auction.tokenId, auction.seller, "AUCTION_CANCELLED"); emit AuctionCancelled(auctionId); } function setAuctionExtensionInterval(uint256 _interval) external onlyOwner { require(_interval > 0, "Invalid interval"); auctionExtensionInterval = _interval; emit AuctionExtensionIntervalUpdated(_interval); } function makeOffer( address collection, uint256 tokenId, address seller, uint256 quantity, uint256 price ) external nonReentrant { require(registeredCollections[collection], "Collection not registered"); require(quantity > 0, "Invalid quantity"); require(price > 0, "Invalid price"); require(seller != address(0), "Invalid seller"); require(seller != msg.sender, "Cannot make offer to self"); uint256 sellerBalance = IERC1155(collection).balanceOf(seller, tokenId); require(sellerBalance >= quantity, "Insufficient seller balance"); _offerIds++; uint256 offerId = _offerIds; offers[collection][tokenId][offerId] = Offer({ buyer: msg.sender, seller: seller, price: price, quantity: quantity, createTime: block.timestamp, status: OfferStatus.PENDING }); userOfferIds[msg.sender].push(offerId); sellerReceivedOffers[seller].push(offerId); tokenOffers[collection][tokenId].push(offerId); offerCollections[offerId] = collection; offerTokenIds[offerId] = tokenId; // Pre-approve marketplace for token transfer designatedToken.transferFrom(msg.sender, address(this), price * quantity); emit OfferCreated(offerId, collection, tokenId, msg.sender, seller, price, quantity); } function acceptOffer(uint256 offerId) external nonReentrant { (address collection, uint256 tokenId, Offer storage offer) = _validateAndGetOffer(offerId); uint256 totalBalance = _validateSellerBalance(collection, tokenId, offer); _validateAndUpdateListing(collection, tokenId, offer.quantity, totalBalance); _processOfferAcceptance(collection, tokenId, offer, offerId); } function _validateAndGetOffer(uint256 offerId) private view returns ( address collection, uint256 tokenId, Offer storage offer ) { collection = offerCollections[offerId]; require(collection != address(0), "Offer does not exist"); tokenId = offerTokenIds[offerId]; offer = offers[collection][tokenId][offerId]; require(offer.status == OfferStatus.PENDING, "Invalid offer status"); require(msg.sender == offer.seller, "Not offer recipient"); return (collection, tokenId, offer); } function _validateSellerBalance( address collection, uint256 tokenId, Offer memory offer ) private view returns (uint256) { uint256 totalBalance = IERC1155(collection).balanceOf(msg.sender, tokenId); require(totalBalance >= offer.quantity, "Insufficient balance"); return totalBalance; } function _validateAndUpdateListing( address collection, uint256 tokenId, uint256 offerQuantity, uint256 totalBalance ) private { Listing storage listing = listings[collection][tokenId][msg.sender]; // Check if NFT is not in active auction if(listing.listingType == ListingType.AUCTION) { require( auctions[listing.auctionId].status != AuctionStatus.ACTIVE, "Active auction exists" ); } // Calculate available quantities uint256 listedQuantity = listing.quantity; uint256 unlistedQuantity = totalBalance - listedQuantity; // Calculate how many NFTs to take from unlisted and listed uint256 takeFromUnlisted = unlistedQuantity >= offerQuantity ? offerQuantity : unlistedQuantity; uint256 takeFromListed = offerQuantity - takeFromUnlisted; // Update listing if needed if(takeFromListed > 0) { if(takeFromListed == listedQuantity) { delete listings[collection][tokenId][msg.sender]; emit ListingRemoved(collection, tokenId, msg.sender, "ZERO_QUANTITY"); } else { listing.quantity = listedQuantity - takeFromListed; emit ListingQuantityUpdated( collection, tokenId, msg.sender, listing.quantity ); } } } function _processOfferAcceptance( address collection, uint256 tokenId, Offer storage offer, uint256 offerId ) private { require( IERC1155(collection).isApprovedForAll(msg.sender, address(this)), "Not approved" ); ICollection.NFTDetails memory nftDetails = ICollection(collection).nftDetails(tokenId); uint256 fee = secondaryFee; if(nftDetails.creator == msg.sender) { fee = primaryFee; } uint16 royaltyPercentage = ICollection(collection).getRoyaltyPercentage(); // Calculate fees uint256 totalPrice = offer.price * offer.quantity; uint256 platformFee = (totalPrice * fee) / 1000; uint256 royaltyFee = (totalPrice * royaltyPercentage) / 1000; uint256 sellerAmount = totalPrice - platformFee - royaltyFee; // Transfer NFT IERC1155(collection).safeTransferFrom( msg.sender, offer.buyer, tokenId, offer.quantity, "" ); // Distribute payments designatedToken.transfer(msg.sender, sellerAmount); if(royaltyFee>0) { designatedToken.transfer(nftDetails.creator, royaltyFee); } offer.status = OfferStatus.ACCEPTED; emit OfferAccepted(offerId, msg.sender); } function rejectOffer(uint256 offerId) external nonReentrant { address collection = offerCollections[offerId]; uint256 tokenId = offerTokenIds[offerId]; require(collection != address(0), "Offer does not exist"); Offer storage offer = offers[collection][tokenId][offerId]; require(offer.status == OfferStatus.PENDING, "Invalid offer status"); require( IERC1155(collection).balanceOf(msg.sender, tokenId) > 0, "Not token owner" ); offer.status = OfferStatus.REJECTED; // Refund buyer designatedToken.transfer(offer.buyer, offer.price * offer.quantity); emit OfferRejected(offerId, msg.sender); } function cancelOffer(uint256 offerId) external nonReentrant { address collection = offerCollections[offerId]; uint256 tokenId = offerTokenIds[offerId]; require(collection != address(0), "Offer does not exist"); Offer storage offer = offers[collection][tokenId][offerId]; require(offer.buyer == msg.sender, "Not offer creator"); require(offer.status == OfferStatus.PENDING, "Invalid offer status"); offer.status = OfferStatus.CANCELLED; // Refund buyer designatedToken.transfer(msg.sender, offer.price * offer.quantity); emit OfferCancelled(offerId, msg.sender); } function getOffersByToken( address collection, uint256 tokenId, uint256 offset, uint256 limit ) external view returns (uint256[] memory offerIdList, uint256 total) { return _getOffersWithFilter( collection, tokenId, address(0), // no user filter offset, limit, 0 // filter type: BY_TOKEN ); } function getOffersToSeller( address seller, uint256 offset, uint256 limit ) external view returns (uint256[] memory offerIdList, uint256 total) { return _getOffersWithFilter( address(0), // no collection filter 0, // no tokenId filter seller, offset, limit, 1 // filter type: BY_SELLER ); } function getOffersByBuyer( address buyer, uint256 offset, uint256 limit ) external view returns (uint256[] memory offerIdList, uint256 total) { return _getOffersWithFilter( address(0), // no collection filter 0, // no tokenId filter buyer, offset, limit, 2 // filter type: BY_BUYER ); } function _getOffersWithFilter( address collection, uint256 tokenId, address user, uint256 offset, uint256 limit, uint8 filterType ) private view returns (uint256[] memory offerIdList, uint256 total) { FilterParams memory params = FilterParams(collection, tokenId, user, filterType); uint256[] storage sourceOffers = _getSourceOffers(user, filterType, params); // Get total count first uint256 count = _countValidOffers(sourceOffers, params); if(count == 0 || offset >= count) { return (new uint256[](0), count); } return _getFilteredOffers(sourceOffers, params, offset, limit, count); } function _getSourceOffers(address user, uint8 filterType, FilterParams memory params) private view returns (uint256[] storage) { if (filterType == 0) { // BY_TOKEN return tokenOffers[params.collection][params.tokenId]; } else if (filterType == 1) { // BY_SELLER return sellerReceivedOffers[user]; } else { // BY_BUYER return userOfferIds[user]; } } function _countValidOffers( uint256[] storage sourceOffers, FilterParams memory params ) private view returns (uint256) { uint256 count; for(uint256 i = 0; i < sourceOffers.length; i++) { if(_isValidOffer(sourceOffers[i], params)) { count++; } } return count; } function _getFilteredOffers( uint256[] storage sourceOffers, FilterParams memory params, uint256 offset, uint256 limit, uint256 count ) private view returns (uint256[] memory offerIdList, uint256) { uint256 size = count - offset; if(size > limit) { size = limit; } offerIdList = new uint256[](size); uint256 currentIndex; uint256 skipped; for(uint256 i = 0; i < sourceOffers.length && currentIndex < size; i++) { uint256 offerId = sourceOffers[i]; if(_isValidOffer(offerId, params)) { if(skipped < offset) { skipped++; continue; } offerIdList[currentIndex++] = offerId; } } return (offerIdList, count); } function _isValidOffer( uint256 offerId, FilterParams memory params ) private view returns (bool) { address offerCollection = offerCollections[offerId]; uint256 offerTokenId = offerTokenIds[offerId]; Offer storage offer = offers[offerCollection][offerTokenId][offerId]; if (params.filterType == 0) { // BY_TOKEN return offerCollection == params.collection && offerTokenId == params.tokenId && offer.status == OfferStatus.PENDING; } else if (params.filterType == 1) { // BY_SELLER return offer.seller == params.user && offer.status == OfferStatus.PENDING; } else { // BY_BUYER return offer.buyer == params.user && offer.status == OfferStatus.PENDING; } } function getOffer(uint256 offerId) external view returns ( address collection, uint256 tokenId, Offer memory offer ) { collection = offerCollections[offerId]; require(collection != address(0), "Offer does not exist"); tokenId = offerTokenIds[offerId]; offer = offers[collection][tokenId][offerId]; return (collection, tokenId, offer); } function batchBuyListedNFTs(BatchPurchaseParams[] calldata params) external nonReentrant { require(params.length > 0, "Empty batch"); for(uint256 i = 0; i < params.length; i++) { BatchPurchaseParams calldata purchase = params[i]; require(registeredCollections[purchase.collection], "Collection not registered"); Listing storage listing = listings[purchase.collection][purchase.tokenId][purchase.seller]; require(listing.seller == purchase.seller && listing.quantity > 0, "Invalid listing"); require(listing.listingType == ListingType.FIXED_PRICE, "Not a fixed price listing"); require(listing.quantity >= purchase.quantity, "Insufficient quantity"); ICollection.NFTDetails memory nftDetails = ICollection(purchase.collection).nftDetails(purchase.tokenId); uint256 fee = secondaryFee; if(nftDetails.creator == purchase.seller) { fee = primaryFee; } uint16 royaltyPercentage = ICollection(purchase.collection).getRoyaltyPercentage(); uint256 totalPrice = listing.price * purchase.quantity; uint256 platformFee = (totalPrice * fee) / 1000; uint256 royaltyFee = (totalPrice * royaltyPercentage) / 1000; uint256 sellerAmount = totalPrice - platformFee - royaltyFee; designatedToken.transferFrom(msg.sender, address(this), platformFee); designatedToken.transferFrom(msg.sender, purchase.seller, sellerAmount); if(royaltyFee>0) { designatedToken.transferFrom(msg.sender, nftDetails.creator, royaltyFee); } IERC1155(purchase.collection).safeTransferFrom( purchase.seller, msg.sender, purchase.tokenId, purchase.quantity, "" ); listing.quantity -= purchase.quantity; if (listing.quantity == 0) { delete listings[purchase.collection][purchase.tokenId][purchase.seller]; emit ListingRemoved(purchase.collection, purchase.tokenId, purchase.seller, "SOLD_OUT"); } emit NFTSold( purchase.collection, purchase.tokenId, purchase.seller, msg.sender, listing.price, purchase.quantity ); } } }
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_designatedToken","internalType":"address"},{"type":"uint256","name":"_primaryFee","internalType":"uint256"},{"type":"uint256","name":"_secondaryFee","internalType":"uint256"}]},{"type":"error","name":"OwnableInvalidOwner","inputs":[{"type":"address","name":"owner","internalType":"address"}]},{"type":"error","name":"OwnableUnauthorizedAccount","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"event","name":"AuctionCancelled","inputs":[{"type":"uint256","name":"auctionId","internalType":"uint256","indexed":true}],"anonymous":false},{"type":"event","name":"AuctionCreated","inputs":[{"type":"uint256","name":"auctionId","internalType":"uint256","indexed":true},{"type":"address","name":"collection","internalType":"address","indexed":true},{"type":"uint256","name":"tokenId","internalType":"uint256","indexed":true},{"type":"address","name":"seller","internalType":"address","indexed":false},{"type":"uint256","name":"startPrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"minBidIncrement","internalType":"uint256","indexed":false},{"type":"uint256","name":"startTime","internalType":"uint256","indexed":false},{"type":"uint256","name":"endTime","internalType":"uint256","indexed":false},{"type":"uint256","name":"quantity","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"AuctionExtended","inputs":[{"type":"uint256","name":"auctionId","internalType":"uint256","indexed":true},{"type":"uint256","name":"newEndTime","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"AuctionExtensionIntervalUpdated","inputs":[{"type":"uint256","name":"newInterval","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"AuctionSettled","inputs":[{"type":"uint256","name":"auctionId","internalType":"uint256","indexed":true},{"type":"address","name":"winner","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"BidPlaced","inputs":[{"type":"uint256","name":"auctionId","internalType":"uint256","indexed":true},{"type":"address","name":"bidder","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"CollectionRegistered","inputs":[{"type":"address","name":"collection","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"FeeUpdated","inputs":[{"type":"bool","name":"isPrimary","internalType":"bool","indexed":false},{"type":"uint256","name":"newFee","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ListingQuantityUpdated","inputs":[{"type":"address","name":"collection","internalType":"address","indexed":true},{"type":"uint256","name":"tokenId","internalType":"uint256","indexed":true},{"type":"address","name":"seller","internalType":"address","indexed":false},{"type":"uint256","name":"newQuantity","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ListingRemoved","inputs":[{"type":"address","name":"collection","internalType":"address","indexed":true},{"type":"uint256","name":"tokenId","internalType":"uint256","indexed":true},{"type":"address","name":"seller","internalType":"address","indexed":false},{"type":"string","name":"reason","internalType":"string","indexed":false}],"anonymous":false},{"type":"event","name":"NFTListed","inputs":[{"type":"address","name":"collection","internalType":"address","indexed":true},{"type":"uint256","name":"tokenId","internalType":"uint256","indexed":true},{"type":"address","name":"seller","internalType":"address","indexed":false},{"type":"uint256","name":"price","internalType":"uint256","indexed":false},{"type":"uint256","name":"quantity","internalType":"uint256","indexed":false},{"type":"uint8","name":"listingType","internalType":"enum NFTMarketplace.ListingType","indexed":false},{"type":"uint256","name":"auctionId","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"NFTSold","inputs":[{"type":"address","name":"collection","internalType":"address","indexed":true},{"type":"uint256","name":"tokenId","internalType":"uint256","indexed":true},{"type":"address","name":"seller","internalType":"address","indexed":false},{"type":"address","name":"buyer","internalType":"address","indexed":false},{"type":"uint256","name":"price","internalType":"uint256","indexed":false},{"type":"uint256","name":"quantity","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"OfferAccepted","inputs":[{"type":"uint256","name":"offerId","internalType":"uint256","indexed":true},{"type":"address","name":"seller","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"OfferCancelled","inputs":[{"type":"uint256","name":"offerId","internalType":"uint256","indexed":true},{"type":"address","name":"buyer","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"OfferCreated","inputs":[{"type":"uint256","name":"offerId","internalType":"uint256","indexed":true},{"type":"address","name":"collection","internalType":"address","indexed":true},{"type":"uint256","name":"tokenId","internalType":"uint256","indexed":true},{"type":"address","name":"buyer","internalType":"address","indexed":false},{"type":"address","name":"seller","internalType":"address","indexed":false},{"type":"uint256","name":"price","internalType":"uint256","indexed":false},{"type":"uint256","name":"quantity","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"OfferRejected","inputs":[{"type":"uint256","name":"offerId","internalType":"uint256","indexed":true},{"type":"address","name":"seller","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"acceptOffer","inputs":[{"type":"uint256","name":"offerId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"auctionCollections","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"auctionExtensionInterval","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"seller","internalType":"address"},{"type":"uint256","name":"startPrice","internalType":"uint256"},{"type":"uint256","name":"currentPrice","internalType":"uint256"},{"type":"uint256","name":"minBidIncrement","internalType":"uint256"},{"type":"uint256","name":"startTime","internalType":"uint256"},{"type":"uint256","name":"endTime","internalType":"uint256"},{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"uint256","name":"quantity","internalType":"uint256"},{"type":"address","name":"highestBidder","internalType":"address"},{"type":"uint8","name":"status","internalType":"enum NFTMarketplace.AuctionStatus"}],"name":"auctions","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"batchBuyListedNFTs","inputs":[{"type":"tuple[]","name":"params","internalType":"struct NFTMarketplace.BatchPurchaseParams[]","components":[{"type":"address","name":"collection","internalType":"address"},{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"address","name":"seller","internalType":"address"},{"type":"uint256","name":"quantity","internalType":"uint256"}]}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"bids","inputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"buyListedNFT","inputs":[{"type":"address","name":"collection","internalType":"address"},{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"address","name":"seller","internalType":"address"},{"type":"uint256","name":"quantity","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"cancelAuction","inputs":[{"type":"uint256","name":"auctionId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"cancelOffer","inputs":[{"type":"uint256","name":"offerId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"collectionFactory","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"createAuction","inputs":[{"type":"address","name":"collection","internalType":"address"},{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"uint256","name":"quantity","internalType":"uint256"},{"type":"uint256","name":"startPrice","internalType":"uint256"},{"type":"uint256","name":"minBidIncrement","internalType":"uint256"},{"type":"uint256","name":"duration","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IERC20"}],"name":"designatedToken","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[]","name":"_collections","internalType":"address[]"},{"type":"uint256","name":"total","internalType":"uint256"}],"name":"getCollectionsByOwner","inputs":[{"type":"address","name":"_owner","internalType":"address"},{"type":"uint256","name":"offset","internalType":"uint256"},{"type":"uint256","name":"limit","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct NFTMarketplace.Listing","components":[{"type":"address","name":"seller","internalType":"address"},{"type":"uint256","name":"price","internalType":"uint256"},{"type":"uint256","name":"quantity","internalType":"uint256"},{"type":"uint8","name":"listingType","internalType":"enum NFTMarketplace.ListingType"},{"type":"uint256","name":"auctionId","internalType":"uint256"}]}],"name":"getListing","inputs":[{"type":"address","name":"collection","internalType":"address"},{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"address","name":"seller","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"collection","internalType":"address"},{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"tuple","name":"offer","internalType":"struct NFTMarketplace.Offer","components":[{"type":"address","name":"buyer","internalType":"address"},{"type":"address","name":"seller","internalType":"address"},{"type":"uint256","name":"price","internalType":"uint256"},{"type":"uint256","name":"quantity","internalType":"uint256"},{"type":"uint256","name":"createTime","internalType":"uint256"},{"type":"uint8","name":"status","internalType":"enum NFTMarketplace.OfferStatus"}]}],"name":"getOffer","inputs":[{"type":"uint256","name":"offerId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"offerIdList","internalType":"uint256[]"},{"type":"uint256","name":"total","internalType":"uint256"}],"name":"getOffersByBuyer","inputs":[{"type":"address","name":"buyer","internalType":"address"},{"type":"uint256","name":"offset","internalType":"uint256"},{"type":"uint256","name":"limit","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"offerIdList","internalType":"uint256[]"},{"type":"uint256","name":"total","internalType":"uint256"}],"name":"getOffersByToken","inputs":[{"type":"address","name":"collection","internalType":"address"},{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"uint256","name":"offset","internalType":"uint256"},{"type":"uint256","name":"limit","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"offerIdList","internalType":"uint256[]"},{"type":"uint256","name":"total","internalType":"uint256"}],"name":"getOffersToSeller","inputs":[{"type":"address","name":"seller","internalType":"address"},{"type":"uint256","name":"offset","internalType":"uint256"},{"type":"uint256","name":"limit","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[]","name":"collections","internalType":"address[]"}],"name":"getRegisteredCollections","inputs":[{"type":"uint256","name":"offset","internalType":"uint256"},{"type":"uint256","name":"limit","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"listNFT","inputs":[{"type":"address","name":"collection","internalType":"address"},{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"uint256","name":"price","internalType":"uint256"},{"type":"uint256","name":"quantity","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"seller","internalType":"address"},{"type":"uint256","name":"price","internalType":"uint256"},{"type":"uint256","name":"quantity","internalType":"uint256"},{"type":"uint8","name":"listingType","internalType":"enum NFTMarketplace.ListingType"},{"type":"uint256","name":"auctionId","internalType":"uint256"}],"name":"listings","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"uint256","name":"","internalType":"uint256"},{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"makeOffer","inputs":[{"type":"address","name":"collection","internalType":"address"},{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"address","name":"seller","internalType":"address"},{"type":"uint256","name":"quantity","internalType":"uint256"},{"type":"uint256","name":"price","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maxAuctionDuration","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"minAuctionDuration","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"buyer","internalType":"address"},{"type":"address","name":"seller","internalType":"address"},{"type":"uint256","name":"price","internalType":"uint256"},{"type":"uint256","name":"quantity","internalType":"uint256"},{"type":"uint256","name":"createTime","internalType":"uint256"},{"type":"uint8","name":"status","internalType":"enum NFTMarketplace.OfferStatus"}],"name":"offers","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bytes4","name":"","internalType":"bytes4"}],"name":"onERC1155BatchReceived","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"address","name":"","internalType":"address"},{"type":"uint256[]","name":"","internalType":"uint256[]"},{"type":"uint256[]","name":"","internalType":"uint256[]"},{"type":"bytes","name":"","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bytes4","name":"","internalType":"bytes4"}],"name":"onERC1155Received","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"address","name":"","internalType":"address"},{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"},{"type":"bytes","name":"","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"placeBid","inputs":[{"type":"uint256","name":"auctionId","internalType":"uint256"},{"type":"uint256","name":"bidAmount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"primaryFee","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"registerCollection","inputs":[{"type":"address","name":"collection","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"registeredCollections","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"rejectOffer","inputs":[{"type":"uint256","name":"offerId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"removeListing","inputs":[{"type":"address","name":"collection","internalType":"address"},{"type":"uint256","name":"tokenId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"secondaryFee","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setAuctionExtensionInterval","inputs":[{"type":"uint256","name":"_interval","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setCollectionFactory","inputs":[{"type":"address","name":"_factory","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setPrimaryFee","inputs":[{"type":"uint256","name":"_fee","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setSecondaryFee","inputs":[{"type":"uint256","name":"_fee","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"settleAuction","inputs":[{"type":"uint256","name":"auctionId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"supportsInterface","inputs":[{"type":"bytes4","name":"interfaceId","internalType":"bytes4"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalCollections","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdrawFees","inputs":[]}]
Contract Creation Code
0x60a06040523480156200001157600080fd5b5060405162005e8938038062005e898339810160408190526200003491620001e9565b33806200005c57604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b620000678162000199565b50600180556001600160a01b038316620000c45760405162461bcd60e51b815260206004820152601560248201527f496e76616c696420746f6b656e20616464726573730000000000000000000000604482015260640162000053565b6103e8821115620001185760405162461bcd60e51b815260206004820152601460248201527f5072696d6172792066656520746f6f2068696768000000000000000000000000604482015260640162000053565b6103e88111156200016c5760405162461bcd60e51b815260206004820152601660248201527f5365636f6e646172792066656520746f6f206869676800000000000000000000604482015260640162000053565b6001600160a01b03909216608052600255600355610e1060085562278d00600955610258600a556200022e565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600080600060608486031215620001ff57600080fd5b83516001600160a01b03811681146200021757600080fd5b602085015160409095015190969495509392505050565b608051615bc8620002c1600039600081816105d901528181610c36015281816112a70152818161134501528181611bdc01528181611c7001528181611d0f0152818161241301528181612490015281816126c70152818161275a01528181612fc40152818161304b01528181613106015281816135bf01528181613b6a01528181614abd0152614b5c0152615bc86000f3fe608060405234801561001057600080fd5b506004361061027f5760003560e01c806359edbe711161015c5780638da5cb5b116100ce578063cf25a2fd11610087578063cf25a2fd146106c4578063d371f24f146106d7578063e3b4367714610700578063ef706adf14610776578063f23a6e6114610789578063f2fde38b146107a857600080fd5b80638da5cb5b1461063957806396b5a7551461064a578063a914607c1461065d578063bc197c8114610666578063bc72157a1461069e578063c815729d146106b157600080fd5b80637561a71d116101205780637561a71d146105a5578063791bb4ef146105ae5780637b1e7675146105c15780637c89d2f0146105d4578063822232021461061357806388b10c751461062657600080fd5b806359edbe711461050257806361d9db2d146105155780636bd3a64b1461051e578063715018a61461058a57806371626bd91461059257600080fd5b8063402d698f116101f5578063476343ee116101b9578063476343ee1461044657806348c9581e1461044e5780635413487614610457578063570ff4de14610460578063571a26a01461046957806357c90de5146104ef57600080fd5b8063402d698f146103be57806341c40576146103d157806342eb81d5146103e45780634579268a1461040457806347518c161461042657600080fd5b80631ba186ce116102475780631ba186ce146103185780631cd8d512146103395780632e9936111461034c57806334277f071461035f5780633c44a5f0146103725780633f1ffcec1461038557600080fd5b806301ffc9a7146102845780630d8264c1146102ac5780630ebf3675146102cf5780630f54a822146102f05780631387c2b514610305575b600080fd5b610297610292366004614f0d565b6107bb565b60405190151581526020015b60405180910390f35b6102976102ba366004614f4c565b600c6020526000908152604090205460ff1681565b6102e26102dd366004614f69565b6107f2565b6040516102a3929190614fa4565b6103036102fe366004614fec565b610813565b005b610303610313366004615005565b6108a4565b61032b610326366004615057565b610d26565b6040516102a39291906150d0565b610303610347366004614fec565b610fa0565b61030361035a366004614fec565b611025565b6102e261036d366004615057565b6115bd565b610303610380366004614f69565b6115dd565b6103b06103933660046150f2565b600f60209081526000928352604080842090915290825290205481565b6040519081526020016102a3565b6103036103cc366004615122565b6118e9565b6103036103df366004614f4c565b611f44565b6103f76103f236600461516a565b6120e0565b6040516102a3919061518c565b610417610412366004614fec565b612206565b6040516102a3939291906151c9565b610439610434366004615233565b612329565b6040516102a39190615285565b6103036123f3565b6103b060095481565b6103b060085481565b6103b060035481565b6104d9610477366004614fec565b600e602052600090815260409020805460018201546002830154600384015460048501546005860154600687015460078801546008909801546001600160a01b039788169896979596949593949293919291811690600160a01b900460ff168a565b6040516102a39a999897969594939291906152cc565b6103036104fd36600461516a565b612534565b61030361051036600461533d565b61288d565b6103b060055481565b61057961052c366004615233565b600b602090815260009384526040808520825292845282842090528252902080546001820154600283015460038401546004909401546001600160a01b03909316939192909160ff169085565b6040516102a3959493929190615369565b610303612b35565b6102e26105a0366004615057565b612b49565b6103b060025481565b6103b06105bc3660046153a4565b612b5d565b6103036105cf3660046153f0565b612bbe565b6105fb7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016102a3565b610303610621366004614fec565b6133b6565b610303610634366004614fec565b613436565b6000546001600160a01b03166105fb565b610303610658366004614fec565b61368e565b6103b0600a5481565b6106856106743660046155d3565b63bc197c8160e01b95945050505050565b6040516001600160e01b031990911681526020016102a3565b6103036106ac366004614f4c565b6138f9565b6103036106bf366004614fec565b613979565b6004546105fb906001600160a01b031681565b6105fb6106e5366004614fec565b6010602052600090815260409020546001600160a01b031681565b61076461070e366004615057565b60116020908152600093845260408085208252928452828420905282529020805460018201546002830154600384015460048501546005909501546001600160a01b039485169593909416939192909160ff1686565b6040516102a396959493929190615681565b610303610784366004614fec565b613a4f565b6106856107973660046156bb565b63f23a6e6160e01b95945050505050565b6103036107b6366004614f4c565b613c36565b60006001600160e01b03198216630271189760e51b14806107ec57506301ffc9a760e01b6001600160e01b03198316145b92915050565b606060006108068686600087876000613c71565b9150915094509492505050565b61081b613d18565b6103e88111156108615760405162461bcd60e51b815260206004820152600c60248201526b08ccaca40e8dede40d0d2ced60a31b60448201526064015b60405180910390fd5b60038190556040805160008152602081018390527fdcabe98a3516480dd980e2164ecede5a6829fda8ff4471d83d8bf3391367815491015b60405180910390a150565b6108ac613d45565b6001600160a01b0385166000908152600c602052604090205460ff166108e45760405162461bcd60e51b815260040161085890615724565b600082116109045760405162461bcd60e51b81526004016108589061575b565b600081116109445760405162461bcd60e51b815260206004820152600d60248201526c496e76616c696420707269636560981b6044820152606401610858565b6001600160a01b03831661098b5760405162461bcd60e51b815260206004820152600e60248201526d24b73b30b634b21039b2b63632b960911b6044820152606401610858565b336001600160a01b038416036109e35760405162461bcd60e51b815260206004820152601960248201527f43616e6e6f74206d616b65206f6666657220746f2073656c66000000000000006044820152606401610858565b604051627eeac760e11b81526000906001600160a01b0387169062fdd58e90610a129087908990600401615785565b602060405180830381865afa158015610a2f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a53919061579e565b905082811015610aa55760405162461bcd60e51b815260206004820152601b60248201527f496e73756666696369656e742073656c6c65722062616c616e636500000000006044820152606401610858565b60078054906000610ab5836157cd565b90915550506007546040805160c0810182523381526001600160a01b03871660208201529081018490526060810185905242608082015260a08101600090526001600160a01b0380891660009081526011602090815260408083208b84528252808320868452825291829020845181549085166001600160a01b0319918216178255918501516001808301805492909616919093161790935590830151600283015560608301516003808401919091556080840151600484015560a08401516005840180549193909260ff19909216918490811115610b9657610b9661519f565b021790555050336000818152601260209081526040808320805460018181018355918552838520018790556001600160a01b038b811685526015845282852080548084018255908652848620018890558d8116808652601685528386208e875285528386208054938401815586528486209092018890558785526013845282852080546001600160a01b03191690921790915560149092529091208990557f00000000000000000000000000000000000000000000000000000000000000001691506323b872dd9030610c6988886157e6565b6040518463ffffffff1660e01b8152600401610c87939291906157fd565b6020604051808303816000875af1158015610ca6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cca9190615821565b5085876001600160a01b0316827f7bfcb39fd55d72b78fc79c395e43811f2690be921ebd660649c546603cbab1673389888a604051610d0c9493929190615843565b60405180910390a45050610d1f60018055565b5050505050565b6060600080805b600554811015610de3576000818152600d6020908152604091829020548251638da5cb5b60e01b815292516001600160a01b0391821693918b16928492638da5cb5b92600480830193928290030181865afa158015610d90573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610db4919061587c565b6001600160a01b031603610dd05782610dcc816157cd565b9350505b5080610ddb816157cd565b915050610d2d565b5080851115610e255760405162461bcd60e51b815260206004820152600e60248201526d125b9d985b1a59081bd9999cd95d60921b6044820152606401610858565b6000610e318683615899565b905084811115610e3e5750835b8067ffffffffffffffff811115610e5757610e57615465565b604051908082528060200260200182016040528015610e80578160200160208202803683370190505b50935060008060005b60055481108015610e9957508383105b15610f91576000818152600d6020908152604091829020548251638da5cb5b60e01b815292516001600160a01b0391821693918e16928492638da5cb5b92600480830193928290030181865afa158015610ef7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f1b919061587c565b6001600160a01b031603610f7d5789831015610f445782610f3b816157cd565b93505050610f7f565b80888581518110610f5757610f576158ac565b6001600160a01b039092166020928302919091019091015283610f79816157cd565b9450505b505b80610f89816157cd565b915050610e89565b50929350505050935093915050565b610fa8613d18565b6103e8811115610fe95760405162461bcd60e51b815260206004820152600c60248201526b08ccaca40e8dede40d0d2ced60a31b6044820152606401610858565b60028190556040805160018152602081018390527fdcabe98a3516480dd980e2164ecede5a6829fda8ff4471d83d8bf339136781549101610899565b61102d613d45565b6000818152600e60205260408120906008820154600160a01b900460ff16600281111561105c5761105c61519f565b146110795760405162461bcd60e51b8152600401610858906158c2565b806005015442116110c05760405162461bcd60e51b8152602060048201526011602482015270105d58dd1a5bdb881b9bdd08195b991959607a1b6044820152606401610858565b60088101546001600160a01b031661110b5760405162461bcd60e51b815260206004820152600e60248201526d139bc8189a591cc81c1b1858d95960921b6044820152606401610858565b600881018054600160a01b60ff60a01b1990911617905560008281526010602052604080822054600284015460068501549251637d4cd84760e01b815260048101939093526001600160a01b039091169290918390637d4cd84790602401600060405180830381865afa158015611186573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526111ae9190810190615953565b6003548554608083015192935090916001600160a01b039182169116036111d457506002545b6000846001600160a01b03166359c8b7dd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611214573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112389190615a23565b905060006103e861124984876157e6565b6112539190615a47565b905060006103e861126861ffff8516886157e6565b6112729190615a47565b90506000816112818489615899565b61128b9190615899565b895460405163a9059cbb60e01b81529192506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081169263a9059cbb926112df9216908590600401615785565b6020604051808303816000875af11580156112fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113229190615821565b5081156113c057608086015160405163a9059cbb60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163a9059cbb9161137b91908690600401615785565b6020604051808303816000875af115801561139a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113be9190615821565b505b600889015460068a015460078b0154604051637921219560e11b81526001600160a01b03808d169463f242432a9461140394309492909316929091600401615a69565b600060405180830381600087803b15801561141d57600080fd5b505af1158015611431573d6000803e3d6000fd5b5050505060008960000160009054906101000a90046001600160a01b03169050600b60008a6001600160a01b03166001600160a01b0316815260200190815260200160002060008b6006015481526020019081526020016000206000826001600160a01b03166001600160a01b03168152602001908152602001600020600080820160006101000a8154906001600160a01b030219169055600182016000905560028201600090556003820160006101000a81549060ff0219169055600482016000905550508960060154896001600160a01b0316600080516020615b738339815191528360405161155991906001600160a01b03919091168152604060208201819052600f908201526e105550d51253d397d4d15515131151608a1b606082015260800190565b60405180910390a360088a01546040518981526001600160a01b03909116908c907fc9f72b276a388619c6d185d146697036241880c36654b1a3ffdad07c24038d999060200160405180910390a3505050505050505050506115ba60018055565b50565b606060006115d16000808787876002613c71565b91509150935093915050565b6115e5613d45565b6001600160a01b0384166000908152600c602052604090205460ff1661161d5760405162461bcd60e51b815260040161085890615724565b6000821161165d5760405162461bcd60e51b815260206004820152600d60248201526c496e76616c696420707269636560981b6044820152606401610858565b6000811161167d5760405162461bcd60e51b81526004016108589061575b565b604051627eeac760e11b815281906001600160a01b0386169062fdd58e906116ab9033908890600401615785565b602060405180830381865afa1580156116c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116ec919061579e565b101561170a5760405162461bcd60e51b815260040161085890615aa1565b6001600160a01b0384166000908152600b60209081526040808320868452825280832033845290915290206002810154158061179b57506001600382015460ff16600181111561175c5761175c61519f565b14801561179b5750600060048201546000908152600e6020526040902060080154600160a01b900460ff1660028111156117985761179861519f565b14155b6117d85760405162461bcd60e51b815260206004820152600e60248201526d105b1c9958591e481b1a5cdd195960921b6044820152606401610858565b6040805160a081018252338152602081018590529081018390526060810160008152600060209182018190526001600160a01b038881168252600b835260408083208984528452808320338452845291829020845181546001600160a01b03191692169190911781559183015160018084019190915590830151600283015560608301516003830180549192909160ff191690838181111561187c5761187c61519f565b02179055506080820151816004015590505083856001600160a01b03167f97e6d0949163c71f57f0ac35f319e1895a30454cba82cfe6b940b9862cc0dbdd3386866000806040516118d1959493929190615369565b60405180910390a3506118e360018055565b50505050565b6118f1613d45565b6001600160a01b0384166000908152600c602052604090205460ff166119295760405162461bcd60e51b815260040161085890615724565b6001600160a01b038085166000908152600b6020908152604080832087845282528083208685168085529252909120805490921614801561196e575060008160020154115b6119ac5760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206c697374696e6760881b6044820152606401610858565b6000600382015460ff1660018111156119c7576119c761519f565b14611a105760405162461bcd60e51b81526020600482015260196024820152784e6f742061206669786564207072696365206c697374696e6760381b6044820152606401610858565b8181600201541015611a5c5760405162461bcd60e51b8152602060048201526015602482015274496e73756666696369656e74207175616e7469747960581b6044820152606401610858565b604051637d4cd84760e01b8152600481018590526000906001600160a01b03871690637d4cd84790602401600060405180830381865afa158015611aa4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611acc9190810190615953565b905060006003549050846001600160a01b031682608001516001600160a01b031603611af757506002545b6000876001600160a01b03166359c8b7dd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b37573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b5b9190615a23565b90506000858560010154611b6f91906157e6565b905060006103e8611b8085846157e6565b611b8a9190615a47565b905060006103e8611b9f61ffff8616856157e6565b611ba99190615a47565b9050600081611bb88486615899565b611bc29190615899565b6040516323b872dd60e01b81529091506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906323b872dd90611c15903390309088906004016157fd565b6020604051808303816000875af1158015611c34573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c589190615821565b506040516323b872dd60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906323b872dd90611ca99033908e9086906004016157fd565b6020604051808303816000875af1158015611cc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cec9190615821565b508115611d8b5760808701516040516323b872dd60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916323b872dd91611d4691339187906004016157fd565b6020604051808303816000875af1158015611d65573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d899190615821565b505b8b6001600160a01b031663f242432a8b338e8d6040518563ffffffff1660e01b8152600401611dbd9493929190615a69565b600060405180830381600087803b158015611dd757600080fd5b505af1158015611deb573d6000803e3d6000fd5b5050505088886002016000828254611e039190615899565b90915550506002880154600003611ee757600b60008d6001600160a01b03166001600160a01b0316815260200190815260200160002060008c815260200190815260200160002060008b6001600160a01b03166001600160a01b03168152602001908152602001600020600080820160006101000a8154906001600160a01b030219169055600182016000905560028201600090556003820160006101000a81549060ff0219169055600482016000905550508a8c6001600160a01b0316600080516020615b738339815191528c604051611ede9190615acf565b60405180910390a35b8a8c6001600160a01b03167f85d6aff492354cbf7fdd7efb2bd8bce059037aef73b968f95d32a417598cbff98c338c600101548e604051611f2b9493929190615843565b60405180910390a350505050505050506118e360018055565b6004546001600160a01b03163314611f9e5760405162461bcd60e51b815260206004820152601960248201527f4f6e6c7920666163746f72792063616e207265676973746572000000000000006044820152606401610858565b6001600160a01b038116611ff45760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420636f6c6c656374696f6e20616464726573730000000000006044820152606401610858565b6001600160a01b0381166000908152600c602052604090205460ff16156120525760405162461bcd60e51b8152602060048201526012602482015271105b1c9958591e481c9959da5cdd195c995960721b6044820152606401610858565b6001600160a01b0381166000818152600c60209081526040808320805460ff19166001179055600580548452600d909252822080546001600160a01b031916909317909255815491906120a4836157cd565b90915550506040516001600160a01b038216907ffb99393fd31547f4a765604f2c2d122ce8ccb313edeef8b951130d8bcca866e990600090a250565b60606005548311156121255760405162461bcd60e51b815260206004820152600e60248201526d125b9d985b1a59081bd9999cd95d60921b6044820152606401610858565b6000836005546121359190615899565b9050828111156121425750815b8067ffffffffffffffff81111561215b5761215b615465565b604051908082528060200260200182016040528015612184578160200160208202803683370190505b50915060005b818110156121fe57600d60006121a08388615b03565b815260200190815260200160002060009054906101000a90046001600160a01b03168382815181106121d4576121d46158ac565b6001600160a01b0390921660209283029190910190910152806121f6816157cd565b91505061218a565b505092915050565b60008061223f6040805160c08101825260008082526020820181905291810182905260608101829052608081018290529060a082015290565b6000848152601360205260409020546001600160a01b03169250826122765760405162461bcd60e51b815260040161085890615b16565b6000848152601460209081526040808320546001600160a01b038088168552601184528285208286528452828520898652845293829020825160c081018452815486168152600182015490951693850193909352600283015491840191909152600380830154606085015260048301546080850152600583015491955060a084019160ff169081111561230b5761230b61519f565b600381111561231c5761231c61519f565b90525090505b9193909250565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091526001600160a01b038085166000908152600b6020908152604080832087845282528083208685168452825291829020825160a08101845281549094168452600180820154928501929092526002810154928401929092526003820154606084019160ff909116908111156123ca576123ca61519f565b60018111156123db576123db61519f565b815260200160048201548152505090505b9392505050565b6123fb613d18565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015612462573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612486919061579e565b905080156115ba577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb6124cf6000546001600160a01b031690565b836040518363ffffffff1660e01b81526004016124ed929190615785565b6020604051808303816000875af115801561250c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125309190615821565b5050565b61253c613d45565b6000828152600e60205260408120906008820154600160a01b900460ff16600281111561256b5761256b61519f565b146125885760405162461bcd60e51b8152600401610858906158c2565b80600501544211156125cc5760405162461bcd60e51b815260206004820152600d60248201526c105d58dd1a5bdb88195b991959609a1b6044820152606401610858565b806003015481600201546125e09190615b03565b82101561261d5760405162461bcd60e51b815260206004820152600b60248201526a42696420746f6f206c6f7760a81b6044820152606401610858565b600a544282600501546126309190615899565b1161267f57600a546126429042615b03565b6005820181905560405190815283907f6e912a3a9105bdd2af817ba5adc14e6c127c1035b5b648faa29ca0d58ab8ff4e9060200160405180910390a25b60088101546000848152600f602090815260408083206001600160a01b039094168084529390915290205481156127435760405163a9059cbb60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906126fe9085908590600401615785565b6020604051808303816000875af115801561271d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127419190615821565b505b6040516323b872dd60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906323b872dd90612793903390309089906004016157fd565b6020604051808303816000875af11580156127b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127d69190615821565b6128145760405162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b6044820152606401610858565b6008830180546001600160a01b03191633908117909155600284018590556000868152600f60209081526040808320848452825291829020879055905186815287917f0e54eff26401bf69b81b26f60bd85ef47f5d85275c1d268d84f68d6897431c47910160405180910390a350505061253060018055565b612895613d45565b6001600160a01b038083166000908152600b60209081526040808320858452825280832033808552925290912080549092161480156128d8575060008160020154115b6129185760405162461bcd60e51b81526020600482015260116024820152704e6f20616374697665206c697374696e6760781b6044820152606401610858565b6001600382015460ff1660018111156129335761293361519f565b03612a865760048101546000908152600e60205260408120906008820154600160a01b900460ff16600281111561296c5761296c61519f565b146129895760405162461bcd60e51b8152600401610858906158c2565b60088101546001600160a01b0316156129da5760405162461bcd60e51b8152602060048201526013602482015272109a591cc8185b1c9958591e481c1b1858d959606a1b6044820152606401610858565b60088101805460ff60a01b1916600160a11b1790556002820154604051637921219560e11b81526001600160a01b0386169163f242432a91612a2491309133918991600401615a69565b600060405180830381600087803b158015612a3e57600080fd5b505af1158015612a52573d6000803e3d6000fd5b5050505060048201546040517f2809c7e17bf978fbc7194c0a694b638c4215e9140cacc6c38ca36010b45697df90600090a2505b6001600160a01b0383166000818152600b6020908152604080832086845282528083203380855290835281842080546001600160a01b0319168155600181018590556002810185905560038101805460ff19169055600401939093558051928352908201819052601190820152702922a6a7ab22a22fa12cafa9a2a62622a960791b6060820152839190600080516020615b738339815191529060800160405180910390a35061253060018055565b612b3d613d18565b612b476000613d9e565b565b606060006115d16000808787876001613c71565b6000612b67613d45565b612b75878787878787613dee565b60068054906000612b85836157cd565b9091555050600654612b9a888888888561413c565b612ba98189898989898961423d565b9050612bb460018055565b9695505050505050565b612bc6613d45565b80612c015760405162461bcd60e51b815260206004820152600b60248201526a08adae0e8f240c4c2e8c6d60ab1b6044820152606401610858565b60005b818110156133ac5736838383818110612c1f57612c1f6158ac565b608002919091019150600c90506000612c3b6020840184614f4c565b6001600160a01b0316815260208101919091526040016000205460ff16612c745760405162461bcd60e51b815260040161085890615724565b6000600b81612c866020850185614f4c565b6001600160a01b03166001600160a01b031681526020019081526020016000206000836020013581526020019081526020016000206000836040016020810190612cd09190614f4c565b6001600160a01b03166001600160a01b031681526020019081526020016000209050816040016020810190612d059190614f4c565b81546001600160a01b039081169116148015612d25575060008160020154115b612d635760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206c697374696e6760881b6044820152606401610858565b6000600382015460ff166001811115612d7e57612d7e61519f565b14612dc75760405162461bcd60e51b81526020600482015260196024820152784e6f742061206669786564207072696365206c697374696e6760381b6044820152606401610858565b816060013581600201541015612e175760405162461bcd60e51b8152602060048201526015602482015274496e73756666696369656e74207175616e7469747960581b6044820152606401610858565b6000612e266020840184614f4c565b604051637d4cd84760e01b8152602085013560048201526001600160a01b039190911690637d4cd84790602401600060405180830381865afa158015612e70573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612e989190810190615953565b600354909150612eae6060850160408601614f4c565b6001600160a01b031682608001516001600160a01b031603612ecf57506002545b6000612ede6020860186614f4c565b6001600160a01b03166359c8b7dd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f3f9190615a23565b9050600085606001358560010154612f5791906157e6565b905060006103e8612f6885846157e6565b612f729190615a47565b905060006103e8612f8761ffff8616856157e6565b612f919190615a47565b9050600081612fa08486615899565b612faa9190615899565b6040516323b872dd60e01b81529091506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906323b872dd90612ffd903390309088906004016157fd565b6020604051808303816000875af115801561301c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130409190615821565b506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166323b872dd3361308160608d0160408e01614f4c565b846040518463ffffffff1660e01b81526004016130a0939291906157fd565b6020604051808303816000875af11580156130bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130e39190615821565b5081156131825760808701516040516323b872dd60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916323b872dd9161313d91339187906004016157fd565b6020604051808303816000875af115801561315c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131809190615821565b505b61318f60208a018a614f4c565b6001600160a01b031663f242432a6131ad60608c0160408d01614f4c565b338c602001358d606001356040518563ffffffff1660e01b81526004016131d79493929190615a69565b600060405180830381600087803b1580156131f157600080fd5b505af1158015613205573d6000803e3d6000fd5b5050505088606001358860020160008282546132219190615899565b9091555050600288015460000361332257600b600061324360208c018c614f4c565b6001600160a01b03166001600160a01b0316815260200190815260200160002060008a60200135815260200190815260200160002060008a604001602081019061328d9190614f4c565b6001600160a01b03168152602080820192909252604001600090812080546001600160a01b0319168155600181018290556002810182905560038101805460ff191690556004015589018035906132e4908b614f4c565b6001600160a01b0316600080516020615b7383398151915261330c60608d0160408e01614f4c565b6040516133199190615acf565b60405180910390a35b60208901803590613333908b614f4c565b6001600160a01b03167f85d6aff492354cbf7fdd7efb2bd8bce059037aef73b968f95d32a417598cbff961336d60608d0160408e01614f4c565b338c600101548e606001356040516133889493929190615843565b60405180910390a350505050505050505080806133a4906157cd565b915050612c04565b5061253060018055565b6133be613d18565b600081116134015760405162461bcd60e51b815260206004820152601060248201526f125b9d985b1a59081a5b9d195c9d985b60821b6044820152606401610858565b600a8190556040518181527f70d2c25f438b055a840aa5b6a9c16e5555b10f0b947ac750dbd16ecefd55e78f90602001610899565b61343e613d45565b6000818152601360209081526040808320546014909252909120546001600160a01b0390911690816134825760405162461bcd60e51b815260040161085890615b16565b6001600160a01b03821660009081526011602090815260408083208484528252808320868452909152812090600582015460ff1660038111156134c7576134c761519f565b146134e45760405162461bcd60e51b815260040161085890615b44565b604051627eeac760e11b81526000906001600160a01b0385169062fdd58e906135139033908790600401615785565b602060405180830381865afa158015613530573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613554919061579e565b116135935760405162461bcd60e51b815260206004820152600f60248201526e2737ba103a37b5b2b71037bbb732b960891b6044820152606401610858565b6005810180546002919060ff191660018302179055508054600382015460028301546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081169363a9059cbb939116916135f491906157e6565b6040518363ffffffff1660e01b8152600401613611929190615785565b6020604051808303816000875af1158015613630573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136549190615821565b50604051339085907f1b15bc319d6f29dd5bcf76cd2b89490ed2fe49f1a31fb6b8624b0029fd85c26590600090a35050506115ba60018055565b613696613d45565b6000818152600e60205260408120906008820154600160a01b900460ff1660028111156136c5576136c561519f565b146136e25760405162461bcd60e51b8152600401610858906158c2565b80546001600160a01b031633146137285760405162461bcd60e51b815260206004820152600a6024820152692737ba1039b2b63632b960b11b6044820152606401610858565b60088101546001600160a01b0316156137795760405162461bcd60e51b8152602060048201526013602482015272109a591cc8185b1c9958591e481c1b1858d959606a1b6044820152606401610858565b60088101805460ff60a01b1916600160a11b17905560008281526010602052604090819020548254600684015460078501549351637921219560e11b81526001600160a01b0393841694859463f242432a946137e094309492909116929091600401615a69565b600060405180830381600087803b1580156137fa57600080fd5b505af115801561380e573d6000803e3d6000fd5b505050506001600160a01b038181166000818152600b602090815260408083206006880180548552908352818420885487168552835281842080546001600160a01b0319168155600181018590556002810185905560038101805460ff19169055600401939093559154865483519516855290840182905260118483015270105550d51253d397d0d05390d153131151607a1b606085015290519092600080516020615b73833981519152919081900360800190a360405183907f2809c7e17bf978fbc7194c0a694b638c4215e9140cacc6c38ca36010b45697df90600090a250506115ba60018055565b613901613d18565b6001600160a01b0381166139575760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420666163746f727920616464726573730000000000000000006044820152606401610858565b600480546001600160a01b0319166001600160a01b0392909216919091179055565b613981613d45565b600080600061398f8461446e565b6040805160c08101825282546001600160a01b03908116825260018401541660208201526002830154918101919091526003808301546060830152600483015460808301526005830154949750929550909350600092613a2492879287929091879160a084019160ff90911690811115613a0b57613a0b61519f565b6003811115613a1c57613a1c61519f565b905250614566565b9050613a368484846003015484614605565b613a4284848488614814565b505050506115ba60018055565b613a57613d45565b6000818152601360209081526040808320546014909252909120546001600160a01b039091169081613a9b5760405162461bcd60e51b815260040161085890615b16565b6001600160a01b0380831660009081526011602090815260408083208584528252808320878452909152902080549091163314613b0e5760405162461bcd60e51b81526020600482015260116024820152702737ba1037b33332b91031b932b0ba37b960791b6044820152606401610858565b6000600582015460ff166003811115613b2957613b2961519f565b14613b465760405162461bcd60e51b815260040161085890615b44565b60058101805460ff1916600390811790915581015460028201546001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163a9059cbb913391613b9c916157e6565b6040518363ffffffff1660e01b8152600401613bb9929190615785565b6020604051808303816000875af1158015613bd8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bfc9190615821565b50604051339085907f1f51377b3e685a0e2419f9bb4ba7c07ec54936353ba3d0fb3c6538dab676622290600090a35050506115ba60018055565b613c3e613d18565b6001600160a01b038116613c6857604051631e4fbdf760e01b815260006004820152602401610858565b6115ba81613d9e565b606060008060405180608001604052808a6001600160a01b03168152602001898152602001886001600160a01b031681526020018560ff1681525090506000613cbb888684614c20565b90506000613cc98284614ca1565b9050801580613cd85750808810155b15613cf85760408051600081526020810190915294509250613d0d915050565b613d0582848a8a85614d03565b945094505050505b965096945050505050565b6000546001600160a01b03163314612b475760405163118cdaa760e01b8152336004820152602401610858565b600260015403613d975760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610858565b6002600155565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b0386166000908152600c602052604090205460ff16613e265760405162461bcd60e51b815260040161085890615724565b60008411613e465760405162461bcd60e51b81526004016108589061575b565b60008311613e8c5760405162461bcd60e51b8152602060048201526013602482015272496e76616c696420737461727420707269636560681b6044820152606401610858565b60008211613edc5760405162461bcd60e51b815260206004820152601960248201527f496e76616c6964206d696e2062696420696e6372656d656e74000000000000006044820152606401610858565b6008548110158015613ef057506009548111155b613f2f5760405162461bcd60e51b815260206004820152601060248201526f24b73b30b634b210323ab930ba34b7b760811b6044820152606401610858565b604051627eeac760e11b815284906001600160a01b0388169062fdd58e90613f5d9033908a90600401615785565b602060405180830381865afa158015613f7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f9e919061579e565b1015613fbc5760405162461bcd60e51b815260040161085890615aa1565b60405163e985e9c560e01b81523360048201523060248201526001600160a01b0387169063e985e9c590604401602060405180830381865afa158015614006573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061402a9190615821565b6140655760405162461bcd60e51b815260206004820152600c60248201526b139bdd08185c1c1c9bdd995960a21b6044820152606401610858565b6001600160a01b0386166000908152600b6020908152604080832088845282528083203384529091529020600281015415806140f657506001600382015460ff1660018111156140b7576140b761519f565b1480156140f65750600060048201546000908152600e6020526040902060080154600160a01b900460ff1660028111156140f3576140f361519f565b14155b6141335760405162461bcd60e51b815260206004820152600e60248201526d105b1c9958591e481b1a5cdd195960921b6044820152606401610858565b50505050505050565b6040805160a081018252338082526020808301868152838501888152600160608601818152608087018990526001600160a01b038d81166000908152600b87528981208e825287528981209781529690955296909420855181546001600160a01b031916941693909317835590518284015551600282015592516003840180549394939192909160ff19169083818111156141d9576141d961519f565b02179055506080820151816004015590505083856001600160a01b03167f97e6d0949163c71f57f0ac35f319e1895a30454cba82cfe6b940b9862cc0dbdd33858760018760405161422e959493929190615369565b60405180910390a35050505050565b42600061424a8383615b03565b9050604051806101400160405280336001600160a01b0316815260200186815260200186815260200185815260200183815260200182815260200188815260200187815260200160006001600160a01b03168152602001600060028111156142b4576142b461519f565b905260008a8152600e6020908152604091829020835181546001600160a01b03199081166001600160a01b0392831617835592850151600183015592840151600280830191909155606085015160038301556080850151600483015560a0850151600583015560c0850151600683015560e08501516007830155610100850151600883018054948516919095169081178555610120860151929492936001600160a81b0319161790600160a01b9084908111156143735761437361519f565b021790555050506000898152601060205260409081902080546001600160a01b0319166001600160a01b038b169081179091559051637921219560e11b815263f242432a906143cc90339030908c908c90600401615a69565b600060405180830381600087803b1580156143e657600080fd5b505af11580156143fa573d6000803e3d6000fd5b50506040805133815260208101899052908101879052606081018590526080810184905260a081018990528992506001600160a01b038b1691508b907f2a7e6a41d497de122134820d2f68c4e648c60cf6f4a1ecb9cd1c3cf37384589f9060c00160405180910390a4505050505050505050565b6000818152601360205260408120546001600160a01b03169080826144a55760405162461bcd60e51b815260040161085890615b16565b50506000828152601460209081526040808320546001600160a01b038516845260118352818420818552835281842086855290925282209091600582015460ff1660038111156144f7576144f761519f565b146145145760405162461bcd60e51b815260040161085890615b44565b60018101546001600160a01b031633146123225760405162461bcd60e51b8152602060048201526013602482015272139bdd081bd999995c881c9958da5c1a595b9d606a1b6044820152606401610858565b600080846001600160a01b031662fdd58e33866040518363ffffffff1660e01b8152600401614596929190615785565b602060405180830381865afa1580156145b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145d7919061579e565b905082606001518110156145fd5760405162461bcd60e51b815260040161085890615aa1565b949350505050565b6001600160a01b0384166000908152600b60209081526040808320868452825280832033845290915290206001600382015460ff16600181111561464b5761464b61519f565b036146c957600060048201546000908152600e6020526040902060080154600160a01b900460ff1660028111156146845761468461519f565b036146c95760405162461bcd60e51b81526020600482015260156024820152744163746976652061756374696f6e2065786973747360581b6044820152606401610858565b600281015460006146da8285615899565b90506000858210156146ec57816146ee565b855b905060006146fc8288615899565b90508015614809578381036147b1576001600160a01b0389166000818152600b602090815260408083208c845282528083203380855290835281842080546001600160a01b0319168155600181018590556002810185905560038101805460ff19169055600401939093558051928352908201819052600d908201526c5a45524f5f5155414e5449545960981b6060820152899190600080516020615b738339815191529060800160405180910390a3614809565b6147bb8185615899565b6002860181905560405189916001600160a01b038c16917f36dba6da50cf7eb05d1a346c00f785d8a335ca42221245492e6e243624ce71fb9161480091339190615785565b60405180910390a35b505050505050505050565b60405163e985e9c560e01b81523360048201523060248201526001600160a01b0385169063e985e9c590604401602060405180830381865afa15801561485e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148829190615821565b6148bd5760405162461bcd60e51b815260206004820152600c60248201526b139bdd08185c1c1c9bdd995960a21b6044820152606401610858565b604051637d4cd84760e01b8152600481018490526000906001600160a01b03861690637d4cd84790602401600060405180830381865afa158015614905573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261492d9190810190615953565b905060006003549050336001600160a01b031682608001516001600160a01b03160361495857506002545b6000866001600160a01b03166359c8b7dd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614998573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149bc9190615a23565b90506000856003015486600201546149d491906157e6565b905060006103e86149e585846157e6565b6149ef9190615a47565b905060006103e8614a0461ffff8616856157e6565b614a0e9190615a47565b9050600081614a1d8486615899565b614a279190615899565b90508a6001600160a01b031663f242432a338b60000160009054906101000a90046001600160a01b03168d8d600301546040518563ffffffff1660e01b8152600401614a769493929190615a69565b600060405180830381600087803b158015614a9057600080fd5b505af1158015614aa4573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016925063a9059cbb9150614af69033908590600401615785565b6020604051808303816000875af1158015614b15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614b399190615821565b508115614bd757608087015160405163a9059cbb60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163a9059cbb91614b9291908690600401615785565b6020604051808303816000875af1158015614bb1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614bd59190615821565b505b60058901805460ff19166001179055604051339089907fa7a40af5a1d0c10a3eb94af90cb008170915e8a71a6aaff052794cd762c72fc090600090a35050505050505050505050565b60008260ff16600003614c5a575080516001600160a01b0316600090815260166020908152604080832082850151845290915290206123ec565b8260ff16600103614c8357506001600160a01b03831660009081526015602052604090206123ec565b506001600160a01b03831660009081526012602052604090206123ec565b60008060005b8454811015614cfb57614cd6858281548110614cc557614cc56158ac565b906000526020600020015485614e19565b15614ce95781614ce5816157cd565b9250505b80614cf3816157cd565b915050614ca7565b509392505050565b6060600080614d128685615899565b905084811115614d1f5750835b8067ffffffffffffffff811115614d3857614d38615465565b604051908082528060200260200182016040528015614d61578160200160208202803683370190505b50925060008060005b8a5481108015614d7957508383105b15614e085760008b8281548110614d9257614d926158ac565b90600052602060002001549050614da9818c614e19565b15614df45789831015614dc95782614dc0816157cd565b93505050614df6565b808785614dd5816157cd565b965081518110614de757614de76158ac565b6020026020010181815250505b505b80614e00816157cd565b915050614d6a565b508593505050509550959350505050565b60008281526013602090815260408083205460148352818420546001600160a01b03909116808552601184528285208286528452828520878652909352908320606085015160ff168403614eb55784516001600160a01b038481169116148015614e865750846020015182145b8015614eab575060005b600582015460ff166003811115614ea957614ea961519f565b145b93505050506107ec565b846060015160ff16600103614eea57604085015160018201546001600160a01b039081169116148015614eab57506000614e90565b604085015181546001600160a01b039081169116148015614eab57506000614e90565b600060208284031215614f1f57600080fd5b81356001600160e01b0319811681146123ec57600080fd5b6001600160a01b03811681146115ba57600080fd5b600060208284031215614f5e57600080fd5b81356123ec81614f37565b60008060008060808587031215614f7f57600080fd5b8435614f8a81614f37565b966020860135965060408601359560600135945092505050565b604080825283519082018190526000906020906060840190828701845b82811015614fdd57815184529284019290840190600101614fc1565b50505092019290925292915050565b600060208284031215614ffe57600080fd5b5035919050565b600080600080600060a0868803121561501d57600080fd5b853561502881614f37565b945060208601359350604086013561503f81614f37565b94979396509394606081013594506080013592915050565b60008060006060848603121561506c57600080fd5b833561507781614f37565b95602085013595506040909401359392505050565b600081518084526020808501945080840160005b838110156150c55781516001600160a01b0316875295820195908201906001016150a0565b509495945050505050565b6040815260006150e3604083018561508c565b90508260208301529392505050565b6000806040838503121561510557600080fd5b82359150602083013561511781614f37565b809150509250929050565b6000806000806080858703121561513857600080fd5b843561514381614f37565b935060208501359250604085013561515a81614f37565b9396929550929360600135925050565b6000806040838503121561517d57600080fd5b50508035926020909101359150565b6020815260006123ec602083018461508c565b634e487b7160e01b600052602160045260246000fd5b600481106151c5576151c561519f565b9052565b60006101008201905060018060a01b0380861683528460208401528084511660408401528060208501511660608401525060408301516080830152606083015160a0830152608083015160c083015260a083015161522a60e08401826151b5565b50949350505050565b60008060006060848603121561524857600080fd5b833561525381614f37565b925060208401359150604084013561526a81614f37565b809150509250925092565b600281106151c5576151c561519f565b81516001600160a01b03168152602080830151908201526040808301519082015260608083015160a08301916152bd90840182615275565b50608092830151919092015290565b6001600160a01b038b81168252602082018b9052604082018a9052606082018990526080820188905260a0820187905260c0820186905260e0820185905283166101008201526101408101600383106153275761532761519f565b826101208301529b9a5050505050505050505050565b6000806040838503121561535057600080fd5b823561535b81614f37565b946020939093013593505050565b6001600160a01b0386168152602081018590526040810184905260a081016153946060830185615275565b8260808301529695505050505050565b60008060008060008060c087890312156153bd57600080fd5b86356153c881614f37565b9860208801359850604088013597606081013597506080810135965060a00135945092505050565b6000806020838503121561540357600080fd5b823567ffffffffffffffff8082111561541b57600080fd5b818501915085601f83011261542f57600080fd5b81358181111561543e57600080fd5b8660208260071b850101111561545357600080fd5b60209290920196919550909350505050565b634e487b7160e01b600052604160045260246000fd5b60405160a0810167ffffffffffffffff8111828210171561549e5761549e615465565b60405290565b604051601f8201601f1916810167ffffffffffffffff811182821017156154cd576154cd615465565b604052919050565b600082601f8301126154e657600080fd5b8135602067ffffffffffffffff82111561550257615502615465565b8160051b6155118282016154a4565b928352848101820192828101908785111561552b57600080fd5b83870192505b8483101561554a57823582529183019190830190615531565b979650505050505050565b600067ffffffffffffffff82111561556f5761556f615465565b50601f01601f191660200190565b600082601f83011261558e57600080fd5b81356155a161559c82615555565b6154a4565b8181528460208386010111156155b657600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a086880312156155eb57600080fd5b85356155f681614f37565b9450602086013561560681614f37565b9350604086013567ffffffffffffffff8082111561562357600080fd5b61562f89838a016154d5565b9450606088013591508082111561564557600080fd5b61565189838a016154d5565b9350608088013591508082111561566757600080fd5b506156748882890161557d565b9150509295509295909350565b6001600160a01b0387811682528616602082015260408101859052606081018490526080810183905260c0810161554a60a08301846151b5565b600080600080600060a086880312156156d357600080fd5b85356156de81614f37565b945060208601356156ee81614f37565b93506040860135925060608601359150608086013567ffffffffffffffff81111561571857600080fd5b6156748882890161557d565b60208082526019908201527f436f6c6c656374696f6e206e6f74207265676973746572656400000000000000604082015260600190565b60208082526010908201526f496e76616c6964207175616e7469747960801b604082015260600190565b6001600160a01b03929092168252602082015260400190565b6000602082840312156157b057600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b6000600182016157df576157df6157b7565b5060010190565b80820281158282048414176107ec576107ec6157b7565b6001600160a01b039384168152919092166020820152604081019190915260600190565b60006020828403121561583357600080fd5b815180151581146123ec57600080fd5b6001600160a01b0394851681529290931660208301526040820152606081019190915260800190565b805161587781614f37565b919050565b60006020828403121561588e57600080fd5b81516123ec81614f37565b818103818111156107ec576107ec6157b7565b634e487b7160e01b600052603260045260246000fd5b60208082526012908201527141756374696f6e206e6f742061637469766560701b604082015260600190565b600082601f8301126158ff57600080fd5b815161590d61559c82615555565b8181526020858184870101111561592357600080fd5b60005b83811015615941578581018201518382018301528101615926565b50600092820101919091529392505050565b60006020828403121561596557600080fd5b815167ffffffffffffffff8082111561597d57600080fd5b9083019060a0828603121561599157600080fd5b61599961547b565b8251828111156159a857600080fd5b6159b4878286016158ee565b8252506020830151828111156159c957600080fd5b6159d5878286016158ee565b6020830152506040830151828111156159ed57600080fd5b6159f9878286016158ee565b60408301525060608301516060820152615a156080840161586c565b608082015295945050505050565b600060208284031215615a3557600080fd5b815161ffff811681146123ec57600080fd5b600082615a6457634e487b7160e01b600052601260045260246000fd5b500490565b6001600160a01b0394851681529290931660208301526040820152606081019190915260a06080820181905260009082015260c00190565b602080825260149082015273496e73756666696369656e742062616c616e636560601b604082015260600190565b6001600160a01b039190911681526040602082018190526008908201526714d3d31117d3d55560c21b606082015260800190565b808201808211156107ec576107ec6157b7565b60208082526014908201527313d999995c88191bd95cc81b9bdd08195e1a5cdd60621b604082015260600190565b602080825260149082015273496e76616c6964206f666665722073746174757360601b60408201526060019056fe17d654f862f895d7741bf4e3234b08875e872e59e08d21c44d35187a60cfa2a2a2646970667358221220c3edabd3ed9176c3cf84b1311065357446e6317fc9f4e00864a2a094d8460e5564736f6c63430008140033000000000000000000000000ad3e1f40ffe9318cd7b83b42d01a8c72fcbb8ca700000000000000000000000000000000000000000000000000000000000000190000000000000000000000000000000000000000000000000000000000000019
Deployed ByteCode
0x608060405234801561001057600080fd5b506004361061027f5760003560e01c806359edbe711161015c5780638da5cb5b116100ce578063cf25a2fd11610087578063cf25a2fd146106c4578063d371f24f146106d7578063e3b4367714610700578063ef706adf14610776578063f23a6e6114610789578063f2fde38b146107a857600080fd5b80638da5cb5b1461063957806396b5a7551461064a578063a914607c1461065d578063bc197c8114610666578063bc72157a1461069e578063c815729d146106b157600080fd5b80637561a71d116101205780637561a71d146105a5578063791bb4ef146105ae5780637b1e7675146105c15780637c89d2f0146105d4578063822232021461061357806388b10c751461062657600080fd5b806359edbe711461050257806361d9db2d146105155780636bd3a64b1461051e578063715018a61461058a57806371626bd91461059257600080fd5b8063402d698f116101f5578063476343ee116101b9578063476343ee1461044657806348c9581e1461044e5780635413487614610457578063570ff4de14610460578063571a26a01461046957806357c90de5146104ef57600080fd5b8063402d698f146103be57806341c40576146103d157806342eb81d5146103e45780634579268a1461040457806347518c161461042657600080fd5b80631ba186ce116102475780631ba186ce146103185780631cd8d512146103395780632e9936111461034c57806334277f071461035f5780633c44a5f0146103725780633f1ffcec1461038557600080fd5b806301ffc9a7146102845780630d8264c1146102ac5780630ebf3675146102cf5780630f54a822146102f05780631387c2b514610305575b600080fd5b610297610292366004614f0d565b6107bb565b60405190151581526020015b60405180910390f35b6102976102ba366004614f4c565b600c6020526000908152604090205460ff1681565b6102e26102dd366004614f69565b6107f2565b6040516102a3929190614fa4565b6103036102fe366004614fec565b610813565b005b610303610313366004615005565b6108a4565b61032b610326366004615057565b610d26565b6040516102a39291906150d0565b610303610347366004614fec565b610fa0565b61030361035a366004614fec565b611025565b6102e261036d366004615057565b6115bd565b610303610380366004614f69565b6115dd565b6103b06103933660046150f2565b600f60209081526000928352604080842090915290825290205481565b6040519081526020016102a3565b6103036103cc366004615122565b6118e9565b6103036103df366004614f4c565b611f44565b6103f76103f236600461516a565b6120e0565b6040516102a3919061518c565b610417610412366004614fec565b612206565b6040516102a3939291906151c9565b610439610434366004615233565b612329565b6040516102a39190615285565b6103036123f3565b6103b060095481565b6103b060085481565b6103b060035481565b6104d9610477366004614fec565b600e602052600090815260409020805460018201546002830154600384015460048501546005860154600687015460078801546008909801546001600160a01b039788169896979596949593949293919291811690600160a01b900460ff168a565b6040516102a39a999897969594939291906152cc565b6103036104fd36600461516a565b612534565b61030361051036600461533d565b61288d565b6103b060055481565b61057961052c366004615233565b600b602090815260009384526040808520825292845282842090528252902080546001820154600283015460038401546004909401546001600160a01b03909316939192909160ff169085565b6040516102a3959493929190615369565b610303612b35565b6102e26105a0366004615057565b612b49565b6103b060025481565b6103b06105bc3660046153a4565b612b5d565b6103036105cf3660046153f0565b612bbe565b6105fb7f000000000000000000000000ad3e1f40ffe9318cd7b83b42d01a8c72fcbb8ca781565b6040516001600160a01b0390911681526020016102a3565b610303610621366004614fec565b6133b6565b610303610634366004614fec565b613436565b6000546001600160a01b03166105fb565b610303610658366004614fec565b61368e565b6103b0600a5481565b6106856106743660046155d3565b63bc197c8160e01b95945050505050565b6040516001600160e01b031990911681526020016102a3565b6103036106ac366004614f4c565b6138f9565b6103036106bf366004614fec565b613979565b6004546105fb906001600160a01b031681565b6105fb6106e5366004614fec565b6010602052600090815260409020546001600160a01b031681565b61076461070e366004615057565b60116020908152600093845260408085208252928452828420905282529020805460018201546002830154600384015460048501546005909501546001600160a01b039485169593909416939192909160ff1686565b6040516102a396959493929190615681565b610303610784366004614fec565b613a4f565b6106856107973660046156bb565b63f23a6e6160e01b95945050505050565b6103036107b6366004614f4c565b613c36565b60006001600160e01b03198216630271189760e51b14806107ec57506301ffc9a760e01b6001600160e01b03198316145b92915050565b606060006108068686600087876000613c71565b9150915094509492505050565b61081b613d18565b6103e88111156108615760405162461bcd60e51b815260206004820152600c60248201526b08ccaca40e8dede40d0d2ced60a31b60448201526064015b60405180910390fd5b60038190556040805160008152602081018390527fdcabe98a3516480dd980e2164ecede5a6829fda8ff4471d83d8bf3391367815491015b60405180910390a150565b6108ac613d45565b6001600160a01b0385166000908152600c602052604090205460ff166108e45760405162461bcd60e51b815260040161085890615724565b600082116109045760405162461bcd60e51b81526004016108589061575b565b600081116109445760405162461bcd60e51b815260206004820152600d60248201526c496e76616c696420707269636560981b6044820152606401610858565b6001600160a01b03831661098b5760405162461bcd60e51b815260206004820152600e60248201526d24b73b30b634b21039b2b63632b960911b6044820152606401610858565b336001600160a01b038416036109e35760405162461bcd60e51b815260206004820152601960248201527f43616e6e6f74206d616b65206f6666657220746f2073656c66000000000000006044820152606401610858565b604051627eeac760e11b81526000906001600160a01b0387169062fdd58e90610a129087908990600401615785565b602060405180830381865afa158015610a2f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a53919061579e565b905082811015610aa55760405162461bcd60e51b815260206004820152601b60248201527f496e73756666696369656e742073656c6c65722062616c616e636500000000006044820152606401610858565b60078054906000610ab5836157cd565b90915550506007546040805160c0810182523381526001600160a01b03871660208201529081018490526060810185905242608082015260a08101600090526001600160a01b0380891660009081526011602090815260408083208b84528252808320868452825291829020845181549085166001600160a01b0319918216178255918501516001808301805492909616919093161790935590830151600283015560608301516003808401919091556080840151600484015560a08401516005840180549193909260ff19909216918490811115610b9657610b9661519f565b021790555050336000818152601260209081526040808320805460018181018355918552838520018790556001600160a01b038b811685526015845282852080548084018255908652848620018890558d8116808652601685528386208e875285528386208054938401815586528486209092018890558785526013845282852080546001600160a01b03191690921790915560149092529091208990557f000000000000000000000000ad3e1f40ffe9318cd7b83b42d01a8c72fcbb8ca71691506323b872dd9030610c6988886157e6565b6040518463ffffffff1660e01b8152600401610c87939291906157fd565b6020604051808303816000875af1158015610ca6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cca9190615821565b5085876001600160a01b0316827f7bfcb39fd55d72b78fc79c395e43811f2690be921ebd660649c546603cbab1673389888a604051610d0c9493929190615843565b60405180910390a45050610d1f60018055565b5050505050565b6060600080805b600554811015610de3576000818152600d6020908152604091829020548251638da5cb5b60e01b815292516001600160a01b0391821693918b16928492638da5cb5b92600480830193928290030181865afa158015610d90573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610db4919061587c565b6001600160a01b031603610dd05782610dcc816157cd565b9350505b5080610ddb816157cd565b915050610d2d565b5080851115610e255760405162461bcd60e51b815260206004820152600e60248201526d125b9d985b1a59081bd9999cd95d60921b6044820152606401610858565b6000610e318683615899565b905084811115610e3e5750835b8067ffffffffffffffff811115610e5757610e57615465565b604051908082528060200260200182016040528015610e80578160200160208202803683370190505b50935060008060005b60055481108015610e9957508383105b15610f91576000818152600d6020908152604091829020548251638da5cb5b60e01b815292516001600160a01b0391821693918e16928492638da5cb5b92600480830193928290030181865afa158015610ef7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f1b919061587c565b6001600160a01b031603610f7d5789831015610f445782610f3b816157cd565b93505050610f7f565b80888581518110610f5757610f576158ac565b6001600160a01b039092166020928302919091019091015283610f79816157cd565b9450505b505b80610f89816157cd565b915050610e89565b50929350505050935093915050565b610fa8613d18565b6103e8811115610fe95760405162461bcd60e51b815260206004820152600c60248201526b08ccaca40e8dede40d0d2ced60a31b6044820152606401610858565b60028190556040805160018152602081018390527fdcabe98a3516480dd980e2164ecede5a6829fda8ff4471d83d8bf339136781549101610899565b61102d613d45565b6000818152600e60205260408120906008820154600160a01b900460ff16600281111561105c5761105c61519f565b146110795760405162461bcd60e51b8152600401610858906158c2565b806005015442116110c05760405162461bcd60e51b8152602060048201526011602482015270105d58dd1a5bdb881b9bdd08195b991959607a1b6044820152606401610858565b60088101546001600160a01b031661110b5760405162461bcd60e51b815260206004820152600e60248201526d139bc8189a591cc81c1b1858d95960921b6044820152606401610858565b600881018054600160a01b60ff60a01b1990911617905560008281526010602052604080822054600284015460068501549251637d4cd84760e01b815260048101939093526001600160a01b039091169290918390637d4cd84790602401600060405180830381865afa158015611186573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526111ae9190810190615953565b6003548554608083015192935090916001600160a01b039182169116036111d457506002545b6000846001600160a01b03166359c8b7dd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611214573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112389190615a23565b905060006103e861124984876157e6565b6112539190615a47565b905060006103e861126861ffff8516886157e6565b6112729190615a47565b90506000816112818489615899565b61128b9190615899565b895460405163a9059cbb60e01b81529192506001600160a01b037f000000000000000000000000ad3e1f40ffe9318cd7b83b42d01a8c72fcbb8ca781169263a9059cbb926112df9216908590600401615785565b6020604051808303816000875af11580156112fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113229190615821565b5081156113c057608086015160405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000ad3e1f40ffe9318cd7b83b42d01a8c72fcbb8ca7169163a9059cbb9161137b91908690600401615785565b6020604051808303816000875af115801561139a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113be9190615821565b505b600889015460068a015460078b0154604051637921219560e11b81526001600160a01b03808d169463f242432a9461140394309492909316929091600401615a69565b600060405180830381600087803b15801561141d57600080fd5b505af1158015611431573d6000803e3d6000fd5b5050505060008960000160009054906101000a90046001600160a01b03169050600b60008a6001600160a01b03166001600160a01b0316815260200190815260200160002060008b6006015481526020019081526020016000206000826001600160a01b03166001600160a01b03168152602001908152602001600020600080820160006101000a8154906001600160a01b030219169055600182016000905560028201600090556003820160006101000a81549060ff0219169055600482016000905550508960060154896001600160a01b0316600080516020615b738339815191528360405161155991906001600160a01b03919091168152604060208201819052600f908201526e105550d51253d397d4d15515131151608a1b606082015260800190565b60405180910390a360088a01546040518981526001600160a01b03909116908c907fc9f72b276a388619c6d185d146697036241880c36654b1a3ffdad07c24038d999060200160405180910390a3505050505050505050506115ba60018055565b50565b606060006115d16000808787876002613c71565b91509150935093915050565b6115e5613d45565b6001600160a01b0384166000908152600c602052604090205460ff1661161d5760405162461bcd60e51b815260040161085890615724565b6000821161165d5760405162461bcd60e51b815260206004820152600d60248201526c496e76616c696420707269636560981b6044820152606401610858565b6000811161167d5760405162461bcd60e51b81526004016108589061575b565b604051627eeac760e11b815281906001600160a01b0386169062fdd58e906116ab9033908890600401615785565b602060405180830381865afa1580156116c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116ec919061579e565b101561170a5760405162461bcd60e51b815260040161085890615aa1565b6001600160a01b0384166000908152600b60209081526040808320868452825280832033845290915290206002810154158061179b57506001600382015460ff16600181111561175c5761175c61519f565b14801561179b5750600060048201546000908152600e6020526040902060080154600160a01b900460ff1660028111156117985761179861519f565b14155b6117d85760405162461bcd60e51b815260206004820152600e60248201526d105b1c9958591e481b1a5cdd195960921b6044820152606401610858565b6040805160a081018252338152602081018590529081018390526060810160008152600060209182018190526001600160a01b038881168252600b835260408083208984528452808320338452845291829020845181546001600160a01b03191692169190911781559183015160018084019190915590830151600283015560608301516003830180549192909160ff191690838181111561187c5761187c61519f565b02179055506080820151816004015590505083856001600160a01b03167f97e6d0949163c71f57f0ac35f319e1895a30454cba82cfe6b940b9862cc0dbdd3386866000806040516118d1959493929190615369565b60405180910390a3506118e360018055565b50505050565b6118f1613d45565b6001600160a01b0384166000908152600c602052604090205460ff166119295760405162461bcd60e51b815260040161085890615724565b6001600160a01b038085166000908152600b6020908152604080832087845282528083208685168085529252909120805490921614801561196e575060008160020154115b6119ac5760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206c697374696e6760881b6044820152606401610858565b6000600382015460ff1660018111156119c7576119c761519f565b14611a105760405162461bcd60e51b81526020600482015260196024820152784e6f742061206669786564207072696365206c697374696e6760381b6044820152606401610858565b8181600201541015611a5c5760405162461bcd60e51b8152602060048201526015602482015274496e73756666696369656e74207175616e7469747960581b6044820152606401610858565b604051637d4cd84760e01b8152600481018590526000906001600160a01b03871690637d4cd84790602401600060405180830381865afa158015611aa4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611acc9190810190615953565b905060006003549050846001600160a01b031682608001516001600160a01b031603611af757506002545b6000876001600160a01b03166359c8b7dd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b37573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b5b9190615a23565b90506000858560010154611b6f91906157e6565b905060006103e8611b8085846157e6565b611b8a9190615a47565b905060006103e8611b9f61ffff8616856157e6565b611ba99190615a47565b9050600081611bb88486615899565b611bc29190615899565b6040516323b872dd60e01b81529091506001600160a01b037f000000000000000000000000ad3e1f40ffe9318cd7b83b42d01a8c72fcbb8ca716906323b872dd90611c15903390309088906004016157fd565b6020604051808303816000875af1158015611c34573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c589190615821565b506040516323b872dd60e01b81526001600160a01b037f000000000000000000000000ad3e1f40ffe9318cd7b83b42d01a8c72fcbb8ca716906323b872dd90611ca99033908e9086906004016157fd565b6020604051808303816000875af1158015611cc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cec9190615821565b508115611d8b5760808701516040516323b872dd60e01b81526001600160a01b037f000000000000000000000000ad3e1f40ffe9318cd7b83b42d01a8c72fcbb8ca716916323b872dd91611d4691339187906004016157fd565b6020604051808303816000875af1158015611d65573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d899190615821565b505b8b6001600160a01b031663f242432a8b338e8d6040518563ffffffff1660e01b8152600401611dbd9493929190615a69565b600060405180830381600087803b158015611dd757600080fd5b505af1158015611deb573d6000803e3d6000fd5b5050505088886002016000828254611e039190615899565b90915550506002880154600003611ee757600b60008d6001600160a01b03166001600160a01b0316815260200190815260200160002060008c815260200190815260200160002060008b6001600160a01b03166001600160a01b03168152602001908152602001600020600080820160006101000a8154906001600160a01b030219169055600182016000905560028201600090556003820160006101000a81549060ff0219169055600482016000905550508a8c6001600160a01b0316600080516020615b738339815191528c604051611ede9190615acf565b60405180910390a35b8a8c6001600160a01b03167f85d6aff492354cbf7fdd7efb2bd8bce059037aef73b968f95d32a417598cbff98c338c600101548e604051611f2b9493929190615843565b60405180910390a350505050505050506118e360018055565b6004546001600160a01b03163314611f9e5760405162461bcd60e51b815260206004820152601960248201527f4f6e6c7920666163746f72792063616e207265676973746572000000000000006044820152606401610858565b6001600160a01b038116611ff45760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420636f6c6c656374696f6e20616464726573730000000000006044820152606401610858565b6001600160a01b0381166000908152600c602052604090205460ff16156120525760405162461bcd60e51b8152602060048201526012602482015271105b1c9958591e481c9959da5cdd195c995960721b6044820152606401610858565b6001600160a01b0381166000818152600c60209081526040808320805460ff19166001179055600580548452600d909252822080546001600160a01b031916909317909255815491906120a4836157cd565b90915550506040516001600160a01b038216907ffb99393fd31547f4a765604f2c2d122ce8ccb313edeef8b951130d8bcca866e990600090a250565b60606005548311156121255760405162461bcd60e51b815260206004820152600e60248201526d125b9d985b1a59081bd9999cd95d60921b6044820152606401610858565b6000836005546121359190615899565b9050828111156121425750815b8067ffffffffffffffff81111561215b5761215b615465565b604051908082528060200260200182016040528015612184578160200160208202803683370190505b50915060005b818110156121fe57600d60006121a08388615b03565b815260200190815260200160002060009054906101000a90046001600160a01b03168382815181106121d4576121d46158ac565b6001600160a01b0390921660209283029190910190910152806121f6816157cd565b91505061218a565b505092915050565b60008061223f6040805160c08101825260008082526020820181905291810182905260608101829052608081018290529060a082015290565b6000848152601360205260409020546001600160a01b03169250826122765760405162461bcd60e51b815260040161085890615b16565b6000848152601460209081526040808320546001600160a01b038088168552601184528285208286528452828520898652845293829020825160c081018452815486168152600182015490951693850193909352600283015491840191909152600380830154606085015260048301546080850152600583015491955060a084019160ff169081111561230b5761230b61519f565b600381111561231c5761231c61519f565b90525090505b9193909250565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091526001600160a01b038085166000908152600b6020908152604080832087845282528083208685168452825291829020825160a08101845281549094168452600180820154928501929092526002810154928401929092526003820154606084019160ff909116908111156123ca576123ca61519f565b60018111156123db576123db61519f565b815260200160048201548152505090505b9392505050565b6123fb613d18565b6040516370a0823160e01b81523060048201526000907f000000000000000000000000ad3e1f40ffe9318cd7b83b42d01a8c72fcbb8ca76001600160a01b0316906370a0823190602401602060405180830381865afa158015612462573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612486919061579e565b905080156115ba577f000000000000000000000000ad3e1f40ffe9318cd7b83b42d01a8c72fcbb8ca76001600160a01b031663a9059cbb6124cf6000546001600160a01b031690565b836040518363ffffffff1660e01b81526004016124ed929190615785565b6020604051808303816000875af115801561250c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125309190615821565b5050565b61253c613d45565b6000828152600e60205260408120906008820154600160a01b900460ff16600281111561256b5761256b61519f565b146125885760405162461bcd60e51b8152600401610858906158c2565b80600501544211156125cc5760405162461bcd60e51b815260206004820152600d60248201526c105d58dd1a5bdb88195b991959609a1b6044820152606401610858565b806003015481600201546125e09190615b03565b82101561261d5760405162461bcd60e51b815260206004820152600b60248201526a42696420746f6f206c6f7760a81b6044820152606401610858565b600a544282600501546126309190615899565b1161267f57600a546126429042615b03565b6005820181905560405190815283907f6e912a3a9105bdd2af817ba5adc14e6c127c1035b5b648faa29ca0d58ab8ff4e9060200160405180910390a25b60088101546000848152600f602090815260408083206001600160a01b039094168084529390915290205481156127435760405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000ad3e1f40ffe9318cd7b83b42d01a8c72fcbb8ca7169063a9059cbb906126fe9085908590600401615785565b6020604051808303816000875af115801561271d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127419190615821565b505b6040516323b872dd60e01b81526001600160a01b037f000000000000000000000000ad3e1f40ffe9318cd7b83b42d01a8c72fcbb8ca716906323b872dd90612793903390309089906004016157fd565b6020604051808303816000875af11580156127b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127d69190615821565b6128145760405162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b6044820152606401610858565b6008830180546001600160a01b03191633908117909155600284018590556000868152600f60209081526040808320848452825291829020879055905186815287917f0e54eff26401bf69b81b26f60bd85ef47f5d85275c1d268d84f68d6897431c47910160405180910390a350505061253060018055565b612895613d45565b6001600160a01b038083166000908152600b60209081526040808320858452825280832033808552925290912080549092161480156128d8575060008160020154115b6129185760405162461bcd60e51b81526020600482015260116024820152704e6f20616374697665206c697374696e6760781b6044820152606401610858565b6001600382015460ff1660018111156129335761293361519f565b03612a865760048101546000908152600e60205260408120906008820154600160a01b900460ff16600281111561296c5761296c61519f565b146129895760405162461bcd60e51b8152600401610858906158c2565b60088101546001600160a01b0316156129da5760405162461bcd60e51b8152602060048201526013602482015272109a591cc8185b1c9958591e481c1b1858d959606a1b6044820152606401610858565b60088101805460ff60a01b1916600160a11b1790556002820154604051637921219560e11b81526001600160a01b0386169163f242432a91612a2491309133918991600401615a69565b600060405180830381600087803b158015612a3e57600080fd5b505af1158015612a52573d6000803e3d6000fd5b5050505060048201546040517f2809c7e17bf978fbc7194c0a694b638c4215e9140cacc6c38ca36010b45697df90600090a2505b6001600160a01b0383166000818152600b6020908152604080832086845282528083203380855290835281842080546001600160a01b0319168155600181018590556002810185905560038101805460ff19169055600401939093558051928352908201819052601190820152702922a6a7ab22a22fa12cafa9a2a62622a960791b6060820152839190600080516020615b738339815191529060800160405180910390a35061253060018055565b612b3d613d18565b612b476000613d9e565b565b606060006115d16000808787876001613c71565b6000612b67613d45565b612b75878787878787613dee565b60068054906000612b85836157cd565b9091555050600654612b9a888888888561413c565b612ba98189898989898961423d565b9050612bb460018055565b9695505050505050565b612bc6613d45565b80612c015760405162461bcd60e51b815260206004820152600b60248201526a08adae0e8f240c4c2e8c6d60ab1b6044820152606401610858565b60005b818110156133ac5736838383818110612c1f57612c1f6158ac565b608002919091019150600c90506000612c3b6020840184614f4c565b6001600160a01b0316815260208101919091526040016000205460ff16612c745760405162461bcd60e51b815260040161085890615724565b6000600b81612c866020850185614f4c565b6001600160a01b03166001600160a01b031681526020019081526020016000206000836020013581526020019081526020016000206000836040016020810190612cd09190614f4c565b6001600160a01b03166001600160a01b031681526020019081526020016000209050816040016020810190612d059190614f4c565b81546001600160a01b039081169116148015612d25575060008160020154115b612d635760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206c697374696e6760881b6044820152606401610858565b6000600382015460ff166001811115612d7e57612d7e61519f565b14612dc75760405162461bcd60e51b81526020600482015260196024820152784e6f742061206669786564207072696365206c697374696e6760381b6044820152606401610858565b816060013581600201541015612e175760405162461bcd60e51b8152602060048201526015602482015274496e73756666696369656e74207175616e7469747960581b6044820152606401610858565b6000612e266020840184614f4c565b604051637d4cd84760e01b8152602085013560048201526001600160a01b039190911690637d4cd84790602401600060405180830381865afa158015612e70573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612e989190810190615953565b600354909150612eae6060850160408601614f4c565b6001600160a01b031682608001516001600160a01b031603612ecf57506002545b6000612ede6020860186614f4c565b6001600160a01b03166359c8b7dd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f3f9190615a23565b9050600085606001358560010154612f5791906157e6565b905060006103e8612f6885846157e6565b612f729190615a47565b905060006103e8612f8761ffff8616856157e6565b612f919190615a47565b9050600081612fa08486615899565b612faa9190615899565b6040516323b872dd60e01b81529091506001600160a01b037f000000000000000000000000ad3e1f40ffe9318cd7b83b42d01a8c72fcbb8ca716906323b872dd90612ffd903390309088906004016157fd565b6020604051808303816000875af115801561301c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130409190615821565b506001600160a01b037f000000000000000000000000ad3e1f40ffe9318cd7b83b42d01a8c72fcbb8ca7166323b872dd3361308160608d0160408e01614f4c565b846040518463ffffffff1660e01b81526004016130a0939291906157fd565b6020604051808303816000875af11580156130bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130e39190615821565b5081156131825760808701516040516323b872dd60e01b81526001600160a01b037f000000000000000000000000ad3e1f40ffe9318cd7b83b42d01a8c72fcbb8ca716916323b872dd9161313d91339187906004016157fd565b6020604051808303816000875af115801561315c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131809190615821565b505b61318f60208a018a614f4c565b6001600160a01b031663f242432a6131ad60608c0160408d01614f4c565b338c602001358d606001356040518563ffffffff1660e01b81526004016131d79493929190615a69565b600060405180830381600087803b1580156131f157600080fd5b505af1158015613205573d6000803e3d6000fd5b5050505088606001358860020160008282546132219190615899565b9091555050600288015460000361332257600b600061324360208c018c614f4c565b6001600160a01b03166001600160a01b0316815260200190815260200160002060008a60200135815260200190815260200160002060008a604001602081019061328d9190614f4c565b6001600160a01b03168152602080820192909252604001600090812080546001600160a01b0319168155600181018290556002810182905560038101805460ff191690556004015589018035906132e4908b614f4c565b6001600160a01b0316600080516020615b7383398151915261330c60608d0160408e01614f4c565b6040516133199190615acf565b60405180910390a35b60208901803590613333908b614f4c565b6001600160a01b03167f85d6aff492354cbf7fdd7efb2bd8bce059037aef73b968f95d32a417598cbff961336d60608d0160408e01614f4c565b338c600101548e606001356040516133889493929190615843565b60405180910390a350505050505050505080806133a4906157cd565b915050612c04565b5061253060018055565b6133be613d18565b600081116134015760405162461bcd60e51b815260206004820152601060248201526f125b9d985b1a59081a5b9d195c9d985b60821b6044820152606401610858565b600a8190556040518181527f70d2c25f438b055a840aa5b6a9c16e5555b10f0b947ac750dbd16ecefd55e78f90602001610899565b61343e613d45565b6000818152601360209081526040808320546014909252909120546001600160a01b0390911690816134825760405162461bcd60e51b815260040161085890615b16565b6001600160a01b03821660009081526011602090815260408083208484528252808320868452909152812090600582015460ff1660038111156134c7576134c761519f565b146134e45760405162461bcd60e51b815260040161085890615b44565b604051627eeac760e11b81526000906001600160a01b0385169062fdd58e906135139033908790600401615785565b602060405180830381865afa158015613530573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613554919061579e565b116135935760405162461bcd60e51b815260206004820152600f60248201526e2737ba103a37b5b2b71037bbb732b960891b6044820152606401610858565b6005810180546002919060ff191660018302179055508054600382015460028301546001600160a01b037f000000000000000000000000ad3e1f40ffe9318cd7b83b42d01a8c72fcbb8ca781169363a9059cbb939116916135f491906157e6565b6040518363ffffffff1660e01b8152600401613611929190615785565b6020604051808303816000875af1158015613630573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136549190615821565b50604051339085907f1b15bc319d6f29dd5bcf76cd2b89490ed2fe49f1a31fb6b8624b0029fd85c26590600090a35050506115ba60018055565b613696613d45565b6000818152600e60205260408120906008820154600160a01b900460ff1660028111156136c5576136c561519f565b146136e25760405162461bcd60e51b8152600401610858906158c2565b80546001600160a01b031633146137285760405162461bcd60e51b815260206004820152600a6024820152692737ba1039b2b63632b960b11b6044820152606401610858565b60088101546001600160a01b0316156137795760405162461bcd60e51b8152602060048201526013602482015272109a591cc8185b1c9958591e481c1b1858d959606a1b6044820152606401610858565b60088101805460ff60a01b1916600160a11b17905560008281526010602052604090819020548254600684015460078501549351637921219560e11b81526001600160a01b0393841694859463f242432a946137e094309492909116929091600401615a69565b600060405180830381600087803b1580156137fa57600080fd5b505af115801561380e573d6000803e3d6000fd5b505050506001600160a01b038181166000818152600b602090815260408083206006880180548552908352818420885487168552835281842080546001600160a01b0319168155600181018590556002810185905560038101805460ff19169055600401939093559154865483519516855290840182905260118483015270105550d51253d397d0d05390d153131151607a1b606085015290519092600080516020615b73833981519152919081900360800190a360405183907f2809c7e17bf978fbc7194c0a694b638c4215e9140cacc6c38ca36010b45697df90600090a250506115ba60018055565b613901613d18565b6001600160a01b0381166139575760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420666163746f727920616464726573730000000000000000006044820152606401610858565b600480546001600160a01b0319166001600160a01b0392909216919091179055565b613981613d45565b600080600061398f8461446e565b6040805160c08101825282546001600160a01b03908116825260018401541660208201526002830154918101919091526003808301546060830152600483015460808301526005830154949750929550909350600092613a2492879287929091879160a084019160ff90911690811115613a0b57613a0b61519f565b6003811115613a1c57613a1c61519f565b905250614566565b9050613a368484846003015484614605565b613a4284848488614814565b505050506115ba60018055565b613a57613d45565b6000818152601360209081526040808320546014909252909120546001600160a01b039091169081613a9b5760405162461bcd60e51b815260040161085890615b16565b6001600160a01b0380831660009081526011602090815260408083208584528252808320878452909152902080549091163314613b0e5760405162461bcd60e51b81526020600482015260116024820152702737ba1037b33332b91031b932b0ba37b960791b6044820152606401610858565b6000600582015460ff166003811115613b2957613b2961519f565b14613b465760405162461bcd60e51b815260040161085890615b44565b60058101805460ff1916600390811790915581015460028201546001600160a01b037f000000000000000000000000ad3e1f40ffe9318cd7b83b42d01a8c72fcbb8ca7169163a9059cbb913391613b9c916157e6565b6040518363ffffffff1660e01b8152600401613bb9929190615785565b6020604051808303816000875af1158015613bd8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bfc9190615821565b50604051339085907f1f51377b3e685a0e2419f9bb4ba7c07ec54936353ba3d0fb3c6538dab676622290600090a35050506115ba60018055565b613c3e613d18565b6001600160a01b038116613c6857604051631e4fbdf760e01b815260006004820152602401610858565b6115ba81613d9e565b606060008060405180608001604052808a6001600160a01b03168152602001898152602001886001600160a01b031681526020018560ff1681525090506000613cbb888684614c20565b90506000613cc98284614ca1565b9050801580613cd85750808810155b15613cf85760408051600081526020810190915294509250613d0d915050565b613d0582848a8a85614d03565b945094505050505b965096945050505050565b6000546001600160a01b03163314612b475760405163118cdaa760e01b8152336004820152602401610858565b600260015403613d975760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610858565b6002600155565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b0386166000908152600c602052604090205460ff16613e265760405162461bcd60e51b815260040161085890615724565b60008411613e465760405162461bcd60e51b81526004016108589061575b565b60008311613e8c5760405162461bcd60e51b8152602060048201526013602482015272496e76616c696420737461727420707269636560681b6044820152606401610858565b60008211613edc5760405162461bcd60e51b815260206004820152601960248201527f496e76616c6964206d696e2062696420696e6372656d656e74000000000000006044820152606401610858565b6008548110158015613ef057506009548111155b613f2f5760405162461bcd60e51b815260206004820152601060248201526f24b73b30b634b210323ab930ba34b7b760811b6044820152606401610858565b604051627eeac760e11b815284906001600160a01b0388169062fdd58e90613f5d9033908a90600401615785565b602060405180830381865afa158015613f7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f9e919061579e565b1015613fbc5760405162461bcd60e51b815260040161085890615aa1565b60405163e985e9c560e01b81523360048201523060248201526001600160a01b0387169063e985e9c590604401602060405180830381865afa158015614006573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061402a9190615821565b6140655760405162461bcd60e51b815260206004820152600c60248201526b139bdd08185c1c1c9bdd995960a21b6044820152606401610858565b6001600160a01b0386166000908152600b6020908152604080832088845282528083203384529091529020600281015415806140f657506001600382015460ff1660018111156140b7576140b761519f565b1480156140f65750600060048201546000908152600e6020526040902060080154600160a01b900460ff1660028111156140f3576140f361519f565b14155b6141335760405162461bcd60e51b815260206004820152600e60248201526d105b1c9958591e481b1a5cdd195960921b6044820152606401610858565b50505050505050565b6040805160a081018252338082526020808301868152838501888152600160608601818152608087018990526001600160a01b038d81166000908152600b87528981208e825287528981209781529690955296909420855181546001600160a01b031916941693909317835590518284015551600282015592516003840180549394939192909160ff19169083818111156141d9576141d961519f565b02179055506080820151816004015590505083856001600160a01b03167f97e6d0949163c71f57f0ac35f319e1895a30454cba82cfe6b940b9862cc0dbdd33858760018760405161422e959493929190615369565b60405180910390a35050505050565b42600061424a8383615b03565b9050604051806101400160405280336001600160a01b0316815260200186815260200186815260200185815260200183815260200182815260200188815260200187815260200160006001600160a01b03168152602001600060028111156142b4576142b461519f565b905260008a8152600e6020908152604091829020835181546001600160a01b03199081166001600160a01b0392831617835592850151600183015592840151600280830191909155606085015160038301556080850151600483015560a0850151600583015560c0850151600683015560e08501516007830155610100850151600883018054948516919095169081178555610120860151929492936001600160a81b0319161790600160a01b9084908111156143735761437361519f565b021790555050506000898152601060205260409081902080546001600160a01b0319166001600160a01b038b169081179091559051637921219560e11b815263f242432a906143cc90339030908c908c90600401615a69565b600060405180830381600087803b1580156143e657600080fd5b505af11580156143fa573d6000803e3d6000fd5b50506040805133815260208101899052908101879052606081018590526080810184905260a081018990528992506001600160a01b038b1691508b907f2a7e6a41d497de122134820d2f68c4e648c60cf6f4a1ecb9cd1c3cf37384589f9060c00160405180910390a4505050505050505050565b6000818152601360205260408120546001600160a01b03169080826144a55760405162461bcd60e51b815260040161085890615b16565b50506000828152601460209081526040808320546001600160a01b038516845260118352818420818552835281842086855290925282209091600582015460ff1660038111156144f7576144f761519f565b146145145760405162461bcd60e51b815260040161085890615b44565b60018101546001600160a01b031633146123225760405162461bcd60e51b8152602060048201526013602482015272139bdd081bd999995c881c9958da5c1a595b9d606a1b6044820152606401610858565b600080846001600160a01b031662fdd58e33866040518363ffffffff1660e01b8152600401614596929190615785565b602060405180830381865afa1580156145b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145d7919061579e565b905082606001518110156145fd5760405162461bcd60e51b815260040161085890615aa1565b949350505050565b6001600160a01b0384166000908152600b60209081526040808320868452825280832033845290915290206001600382015460ff16600181111561464b5761464b61519f565b036146c957600060048201546000908152600e6020526040902060080154600160a01b900460ff1660028111156146845761468461519f565b036146c95760405162461bcd60e51b81526020600482015260156024820152744163746976652061756374696f6e2065786973747360581b6044820152606401610858565b600281015460006146da8285615899565b90506000858210156146ec57816146ee565b855b905060006146fc8288615899565b90508015614809578381036147b1576001600160a01b0389166000818152600b602090815260408083208c845282528083203380855290835281842080546001600160a01b0319168155600181018590556002810185905560038101805460ff19169055600401939093558051928352908201819052600d908201526c5a45524f5f5155414e5449545960981b6060820152899190600080516020615b738339815191529060800160405180910390a3614809565b6147bb8185615899565b6002860181905560405189916001600160a01b038c16917f36dba6da50cf7eb05d1a346c00f785d8a335ca42221245492e6e243624ce71fb9161480091339190615785565b60405180910390a35b505050505050505050565b60405163e985e9c560e01b81523360048201523060248201526001600160a01b0385169063e985e9c590604401602060405180830381865afa15801561485e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148829190615821565b6148bd5760405162461bcd60e51b815260206004820152600c60248201526b139bdd08185c1c1c9bdd995960a21b6044820152606401610858565b604051637d4cd84760e01b8152600481018490526000906001600160a01b03861690637d4cd84790602401600060405180830381865afa158015614905573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261492d9190810190615953565b905060006003549050336001600160a01b031682608001516001600160a01b03160361495857506002545b6000866001600160a01b03166359c8b7dd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614998573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149bc9190615a23565b90506000856003015486600201546149d491906157e6565b905060006103e86149e585846157e6565b6149ef9190615a47565b905060006103e8614a0461ffff8616856157e6565b614a0e9190615a47565b9050600081614a1d8486615899565b614a279190615899565b90508a6001600160a01b031663f242432a338b60000160009054906101000a90046001600160a01b03168d8d600301546040518563ffffffff1660e01b8152600401614a769493929190615a69565b600060405180830381600087803b158015614a9057600080fd5b505af1158015614aa4573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000ad3e1f40ffe9318cd7b83b42d01a8c72fcbb8ca716925063a9059cbb9150614af69033908590600401615785565b6020604051808303816000875af1158015614b15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614b399190615821565b508115614bd757608087015160405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000ad3e1f40ffe9318cd7b83b42d01a8c72fcbb8ca7169163a9059cbb91614b9291908690600401615785565b6020604051808303816000875af1158015614bb1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614bd59190615821565b505b60058901805460ff19166001179055604051339089907fa7a40af5a1d0c10a3eb94af90cb008170915e8a71a6aaff052794cd762c72fc090600090a35050505050505050505050565b60008260ff16600003614c5a575080516001600160a01b0316600090815260166020908152604080832082850151845290915290206123ec565b8260ff16600103614c8357506001600160a01b03831660009081526015602052604090206123ec565b506001600160a01b03831660009081526012602052604090206123ec565b60008060005b8454811015614cfb57614cd6858281548110614cc557614cc56158ac565b906000526020600020015485614e19565b15614ce95781614ce5816157cd565b9250505b80614cf3816157cd565b915050614ca7565b509392505050565b6060600080614d128685615899565b905084811115614d1f5750835b8067ffffffffffffffff811115614d3857614d38615465565b604051908082528060200260200182016040528015614d61578160200160208202803683370190505b50925060008060005b8a5481108015614d7957508383105b15614e085760008b8281548110614d9257614d926158ac565b90600052602060002001549050614da9818c614e19565b15614df45789831015614dc95782614dc0816157cd565b93505050614df6565b808785614dd5816157cd565b965081518110614de757614de76158ac565b6020026020010181815250505b505b80614e00816157cd565b915050614d6a565b508593505050509550959350505050565b60008281526013602090815260408083205460148352818420546001600160a01b03909116808552601184528285208286528452828520878652909352908320606085015160ff168403614eb55784516001600160a01b038481169116148015614e865750846020015182145b8015614eab575060005b600582015460ff166003811115614ea957614ea961519f565b145b93505050506107ec565b846060015160ff16600103614eea57604085015160018201546001600160a01b039081169116148015614eab57506000614e90565b604085015181546001600160a01b039081169116148015614eab57506000614e90565b600060208284031215614f1f57600080fd5b81356001600160e01b0319811681146123ec57600080fd5b6001600160a01b03811681146115ba57600080fd5b600060208284031215614f5e57600080fd5b81356123ec81614f37565b60008060008060808587031215614f7f57600080fd5b8435614f8a81614f37565b966020860135965060408601359560600135945092505050565b604080825283519082018190526000906020906060840190828701845b82811015614fdd57815184529284019290840190600101614fc1565b50505092019290925292915050565b600060208284031215614ffe57600080fd5b5035919050565b600080600080600060a0868803121561501d57600080fd5b853561502881614f37565b945060208601359350604086013561503f81614f37565b94979396509394606081013594506080013592915050565b60008060006060848603121561506c57600080fd5b833561507781614f37565b95602085013595506040909401359392505050565b600081518084526020808501945080840160005b838110156150c55781516001600160a01b0316875295820195908201906001016150a0565b509495945050505050565b6040815260006150e3604083018561508c565b90508260208301529392505050565b6000806040838503121561510557600080fd5b82359150602083013561511781614f37565b809150509250929050565b6000806000806080858703121561513857600080fd5b843561514381614f37565b935060208501359250604085013561515a81614f37565b9396929550929360600135925050565b6000806040838503121561517d57600080fd5b50508035926020909101359150565b6020815260006123ec602083018461508c565b634e487b7160e01b600052602160045260246000fd5b600481106151c5576151c561519f565b9052565b60006101008201905060018060a01b0380861683528460208401528084511660408401528060208501511660608401525060408301516080830152606083015160a0830152608083015160c083015260a083015161522a60e08401826151b5565b50949350505050565b60008060006060848603121561524857600080fd5b833561525381614f37565b925060208401359150604084013561526a81614f37565b809150509250925092565b600281106151c5576151c561519f565b81516001600160a01b03168152602080830151908201526040808301519082015260608083015160a08301916152bd90840182615275565b50608092830151919092015290565b6001600160a01b038b81168252602082018b9052604082018a9052606082018990526080820188905260a0820187905260c0820186905260e0820185905283166101008201526101408101600383106153275761532761519f565b826101208301529b9a5050505050505050505050565b6000806040838503121561535057600080fd5b823561535b81614f37565b946020939093013593505050565b6001600160a01b0386168152602081018590526040810184905260a081016153946060830185615275565b8260808301529695505050505050565b60008060008060008060c087890312156153bd57600080fd5b86356153c881614f37565b9860208801359850604088013597606081013597506080810135965060a00135945092505050565b6000806020838503121561540357600080fd5b823567ffffffffffffffff8082111561541b57600080fd5b818501915085601f83011261542f57600080fd5b81358181111561543e57600080fd5b8660208260071b850101111561545357600080fd5b60209290920196919550909350505050565b634e487b7160e01b600052604160045260246000fd5b60405160a0810167ffffffffffffffff8111828210171561549e5761549e615465565b60405290565b604051601f8201601f1916810167ffffffffffffffff811182821017156154cd576154cd615465565b604052919050565b600082601f8301126154e657600080fd5b8135602067ffffffffffffffff82111561550257615502615465565b8160051b6155118282016154a4565b928352848101820192828101908785111561552b57600080fd5b83870192505b8483101561554a57823582529183019190830190615531565b979650505050505050565b600067ffffffffffffffff82111561556f5761556f615465565b50601f01601f191660200190565b600082601f83011261558e57600080fd5b81356155a161559c82615555565b6154a4565b8181528460208386010111156155b657600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a086880312156155eb57600080fd5b85356155f681614f37565b9450602086013561560681614f37565b9350604086013567ffffffffffffffff8082111561562357600080fd5b61562f89838a016154d5565b9450606088013591508082111561564557600080fd5b61565189838a016154d5565b9350608088013591508082111561566757600080fd5b506156748882890161557d565b9150509295509295909350565b6001600160a01b0387811682528616602082015260408101859052606081018490526080810183905260c0810161554a60a08301846151b5565b600080600080600060a086880312156156d357600080fd5b85356156de81614f37565b945060208601356156ee81614f37565b93506040860135925060608601359150608086013567ffffffffffffffff81111561571857600080fd5b6156748882890161557d565b60208082526019908201527f436f6c6c656374696f6e206e6f74207265676973746572656400000000000000604082015260600190565b60208082526010908201526f496e76616c6964207175616e7469747960801b604082015260600190565b6001600160a01b03929092168252602082015260400190565b6000602082840312156157b057600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b6000600182016157df576157df6157b7565b5060010190565b80820281158282048414176107ec576107ec6157b7565b6001600160a01b039384168152919092166020820152604081019190915260600190565b60006020828403121561583357600080fd5b815180151581146123ec57600080fd5b6001600160a01b0394851681529290931660208301526040820152606081019190915260800190565b805161587781614f37565b919050565b60006020828403121561588e57600080fd5b81516123ec81614f37565b818103818111156107ec576107ec6157b7565b634e487b7160e01b600052603260045260246000fd5b60208082526012908201527141756374696f6e206e6f742061637469766560701b604082015260600190565b600082601f8301126158ff57600080fd5b815161590d61559c82615555565b8181526020858184870101111561592357600080fd5b60005b83811015615941578581018201518382018301528101615926565b50600092820101919091529392505050565b60006020828403121561596557600080fd5b815167ffffffffffffffff8082111561597d57600080fd5b9083019060a0828603121561599157600080fd5b61599961547b565b8251828111156159a857600080fd5b6159b4878286016158ee565b8252506020830151828111156159c957600080fd5b6159d5878286016158ee565b6020830152506040830151828111156159ed57600080fd5b6159f9878286016158ee565b60408301525060608301516060820152615a156080840161586c565b608082015295945050505050565b600060208284031215615a3557600080fd5b815161ffff811681146123ec57600080fd5b600082615a6457634e487b7160e01b600052601260045260246000fd5b500490565b6001600160a01b0394851681529290931660208301526040820152606081019190915260a06080820181905260009082015260c00190565b602080825260149082015273496e73756666696369656e742062616c616e636560601b604082015260600190565b6001600160a01b039190911681526040602082018190526008908201526714d3d31117d3d55560c21b606082015260800190565b808201808211156107ec576107ec6157b7565b60208082526014908201527313d999995c88191bd95cc81b9bdd08195e1a5cdd60621b604082015260600190565b602080825260149082015273496e76616c6964206f666665722073746174757360601b60408201526060019056fe17d654f862f895d7741bf4e3234b08875e872e59e08d21c44d35187a60cfa2a2a2646970667358221220c3edabd3ed9176c3cf84b1311065357446e6317fc9f4e00864a2a094d8460e5564736f6c63430008140033