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
- 100
- EVM Version
- paris
- Verified at
- 2025-06-08T13:11:14.270041Z
Constructor Arguments
0x000000000000000000000000ad3e1f40ffe9318cd7b83b42d01a8c72fcbb8ca700000000000000000000000000000000000000000000000000000000000000190000000000000000000000000000000000000000000000000000000000000019
Arg [0] (address) : 0xad3e1f40ffe9318cd7b83b42d01a8c72fcbb8ca7
Arg [1] (uint256) : 25
Arg [2] (uint256) : 25
Contract source code
// Sources flattened with hardhat v2.24.2 https://hardhat.org // SPDX-License-Identifier: MIT // File @openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol@v5.3.0 // Original license: SPDX_License_Identifier: MIT // 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@v5.3.0 // Original license: SPDX_License_Identifier: MIT // 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@v5.3.0 // Original license: SPDX_License_Identifier: MIT // 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 @openzeppelin/contracts/utils/Context.sol@v5.3.0 // Original license: SPDX_License_Identifier: MIT // 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@v5.3.0 // Original license: SPDX_License_Identifier: MIT // 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/utils/introspection/IERC165.sol@v5.3.0 // Original license: SPDX_License_Identifier: MIT // 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@v5.3.0 // Original license: SPDX_License_Identifier: MIT // OpenZeppelin Contracts (last updated v5.3.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 {IERC1155Receiver-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 {IERC1155Receiver-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/token/ERC1155/IERC1155Receiver.sol@v5.3.0 // Original license: SPDX_License_Identifier: MIT // 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/utils/introspection/ERC165.sol@v5.3.0 // Original license: SPDX_License_Identifier: MIT // 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/utils/ERC1155Holder.sol@v5.3.0 // Original license: SPDX_License_Identifier: MIT // 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/token/ERC721/IERC721.sol@v5.3.0 // Original license: SPDX_License_Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.20; /** * @dev Required interface of an ERC-721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon * a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC-721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or * {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon * a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC-721 * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must * understand this adds an external call which potentially creates a reentrancy vulnerability. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 tokenId) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the address zero. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); } // File @openzeppelin/contracts/token/ERC721/IERC721Receiver.sol@v5.3.0 // Original license: SPDX_License_Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.20; /** * @title ERC-721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC-721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be * reverted. * * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); } // File @openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol@v5.3.0 // Original license: SPDX_License_Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/utils/ERC721Holder.sol) pragma solidity ^0.8.20; /** * @dev Implementation of the {IERC721Receiver} interface. * * Accepts all token transfers. * Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or * {IERC721-setApprovalForAll}. */ abstract contract ERC721Holder is IERC721Receiver { /** * @dev See {IERC721Receiver-onERC721Received}. * * Always returns `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received(address, address, uint256, bytes memory) public virtual returns (bytes4) { return this.onERC721Received.selector; } } // File @openzeppelin/contracts/token/ERC20/IERC20.sol@v5.3.0 // Original license: SPDX_License_Identifier: MIT // 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/ReentrancyGuard.sol@v5.3.0 // Original license: SPDX_License_Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol) pragma solidity ^0.8.20; /** * @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 EIP-1153 (transient storage) is available on the chain you're deploying at, * consider using {ReentrancyGuardTransient} instead. * * 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; /** * @dev Unauthorized reentrant call. */ error ReentrancyGuardReentrantCall(); 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 if (_status == ENTERED) { revert ReentrancyGuardReentrantCall(); } // 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 contracts/interfaces/ICollection.sol // Original license: SPDX_License_Identifier: MIT pragma solidity ^0.8.20; 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 ) external; function createNFT( string memory name, string memory description, string memory _tokenURI, uint256 maxSupply, address user ) external returns (uint256); function getCreator(uint256 tokenId) external view returns (address); function getRoyaltyPercentage() external view returns(uint16); function updateRoyaltyPercentage(uint16 _royaltyPercentage) external; } // File contracts/NFTMarketplace.sol // Original license: SPDX_License_Identifier: MIT pragma solidity ^0.8.20; contract NFTMarketplace is Ownable, ERC1155Holder, ERC721Holder, ReentrancyGuard { enum ListingType { FIXED_PRICE, AUCTION } enum AuctionStatus { ACTIVE, ENDED, CANCELLED } enum OfferStatus { PENDING, ACCEPTED, REJECTED, CANCELLED } enum TokenStandard { ERC1155, ERC721 } struct Listing { address seller; uint256 price; uint256 quantity; // Always 1 for ERC721 ListingType listingType; uint256 auctionId; // 0 for fixed price listings TokenStandard tokenStandard; } struct AuctionDetails { address seller; uint256 startPrice; uint256 currentPrice; uint256 minBidIncrement; uint256 startTime; uint256 endTime; uint256 tokenId; uint256 quantity; address highestBidder; AuctionStatus status; TokenStandard tokenStandard; } struct Offer { address buyer; address seller; uint256 price; uint256 quantity; uint256 createTime; OfferStatus status; TokenStandard tokenStandard; } struct FilterParams { address collection; uint256 tokenId; address user; uint8 filterType; TokenStandard tokenStandard; } struct BatchPurchaseParams { address collection; uint256 tokenId; address seller; uint256 quantity; TokenStandard tokenStandard; } 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, TokenStandard tokenStandard ); event NFTSold( address indexed collection, uint256 indexed tokenId, address seller, address buyer, uint256 price, uint256 quantity, TokenStandard tokenStandard ); 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, TokenStandard tokenStandard ); 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, TokenStandard tokenStandard ); 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 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, TokenStandard tokenStandard ) external nonReentrant { require(registeredCollections[collection], "Collection not registered"); require(price > 0, "Invalid price"); require(quantity > 0, "Invalid quantity"); if (tokenStandard == TokenStandard.ERC721) { require(quantity == 1, "ERC721 quantity must be 1"); require(IERC721(collection).ownerOf(tokenId) == msg.sender, "Not token owner"); require(IERC721(collection).getApproved(tokenId) == address(this) || IERC721(collection).isApprovedForAll(msg.sender, address(this)), "Not approved"); } else { require(IERC1155(collection).balanceOf(msg.sender, tokenId) >= quantity, "Insufficient balance"); require(IERC1155(collection).isApprovedForAll(msg.sender, address(this)), "Not approved"); } // 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, tokenStandard: tokenStandard }); emit NFTListed( collection, tokenId, msg.sender, price, quantity, ListingType.FIXED_PRICE, 0, tokenStandard ); } 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; if (listing.tokenStandard == TokenStandard.ERC721) { IERC721(collection).safeTransferFrom(address(this), msg.sender, tokenId); } else { 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, TokenStandard tokenStandard ) 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"); require(listing.tokenStandard == tokenStandard, "Token standard mismatch"); if (tokenStandard == TokenStandard.ERC721) { require(quantity == 1, "ERC721 quantity must be 1"); } address nftCreator = ICollection(collection).getCreator(tokenId); uint256 fee = secondaryFee; if(nftCreator == 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, nftCreator, royaltyFee); } if (tokenStandard == TokenStandard.ERC721) { IERC721(collection).safeTransferFrom(seller, msg.sender, tokenId); } else { 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, tokenStandard); } 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, TokenStandard tokenStandard ) external nonReentrant returns (uint256) { _validateAuctionParams( collection, tokenId, quantity, startPrice, minBidIncrement, duration, tokenStandard ); _auctionIds++; uint256 auctionId = _auctionIds; _createAuctionListing( collection, tokenId, quantity, startPrice, auctionId, tokenStandard ); _setupAuction( auctionId, collection, tokenId, quantity, startPrice, minBidIncrement, duration, tokenStandard ); return auctionId; } function _validateAuctionParams( address collection, uint256 tokenId, uint256 quantity, uint256 startPrice, uint256 minBidIncrement, uint256 duration, TokenStandard tokenStandard ) 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"); if (tokenStandard == TokenStandard.ERC721) { require(quantity == 1, "ERC721 quantity must be 1"); require(IERC721(collection).ownerOf(tokenId) == msg.sender, "Not token owner"); require(IERC721(collection).getApproved(tokenId) == address(this) || IERC721(collection).isApprovedForAll(msg.sender, address(this)), "Not approved"); } else { 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, TokenStandard tokenStandard ) internal { listings[collection][tokenId][msg.sender] = Listing({ seller: msg.sender, price: startPrice, quantity: quantity, listingType: ListingType.AUCTION, auctionId: auctionId, tokenStandard: tokenStandard }); emit NFTListed( collection, tokenId, msg.sender, startPrice, quantity, ListingType.AUCTION, auctionId, tokenStandard ); } function _setupAuction( uint256 auctionId, address collection, uint256 tokenId, uint256 quantity, uint256 startPrice, uint256 minBidIncrement, uint256 duration, TokenStandard tokenStandard ) 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, tokenStandard: tokenStandard }); auctionCollections[auctionId] = collection; if (tokenStandard == TokenStandard.ERC721) { IERC721(collection).safeTransferFrom(msg.sender, address(this), tokenId); } else { IERC1155(collection).safeTransferFrom(msg.sender, address(this), tokenId, quantity, ""); } emit AuctionCreated( auctionId, collection, tokenId, msg.sender, startPrice, minBidIncrement, startTime, endTime, quantity, tokenStandard ); } 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; address creator = ICollection(collection).getCreator(auction.tokenId); uint256 fee = secondaryFee; if(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(creator, royaltyFee); } // Transfer NFT if (auction.tokenStandard == TokenStandard.ERC721) { IERC721(collection).safeTransferFrom(address(this), auction.highestBidder, auction.tokenId); } else { 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]; if (auction.tokenStandard == TokenStandard.ERC721) { IERC721(collection).safeTransferFrom(address(this), auction.seller, auction.tokenId); } else { 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, TokenStandard tokenStandard ) 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"); if (tokenStandard == TokenStandard.ERC721) { require(quantity == 1, "ERC721 quantity must be 1"); require(IERC721(collection).ownerOf(tokenId) == seller, "Seller not owner"); } else { require(IERC1155(collection).balanceOf(seller, tokenId) >= 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, tokenStandard: tokenStandard }); 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,tokenStandard); } 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) { if (offer.tokenStandard == TokenStandard.ERC721) { require(IERC721(collection).ownerOf(tokenId) == msg.sender, "Not token owner"); return 1; } else { 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( offer.tokenStandard == TokenStandard.ERC721 ? IERC721(collection).getApproved(tokenId) == address(this) || IERC721(collection).isApprovedForAll(msg.sender, address(this)) : IERC1155(collection).isApprovedForAll(msg.sender, address(this)), "Not approved" ); address creator = ICollection(collection).getCreator(tokenId); uint256 fee = secondaryFee; if(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; if (offer.tokenStandard == TokenStandard.ERC721) { IERC721(collection).safeTransferFrom(msg.sender, offer.buyer, tokenId); } else { IERC1155(collection).safeTransferFrom(msg.sender, offer.buyer, tokenId, offer.quantity, ""); } // Distribute payments designatedToken.transfer(msg.sender, sellerAmount); if(royaltyFee>0) { designatedToken.transfer(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( offer.tokenStandard == TokenStandard.ERC721 ? IERC721(collection).ownerOf(tokenId) == msg.sender : 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, TokenStandard tokenStandard ) external view returns (uint256[] memory offerIdList, uint256 total) { return _getOffersWithFilter( collection, tokenId, address(0), // no user filter offset, limit, 0,// filter type: BY_TOKEN tokenStandard ); } 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 TokenStandard.ERC1155 ); } 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 TokenStandard.ERC1155 ); } function _getOffersWithFilter( address collection, uint256 tokenId, address user, uint256 offset, uint256 limit, uint8 filterType, TokenStandard tokenStandard ) private view returns (uint256[] memory offerIdList, uint256 total) { FilterParams memory params = FilterParams(collection, tokenId, user, filterType, tokenStandard); 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"); // address creator = ICollection(purchase.collection).getCreator(purchase.tokenId); // uint256 fee = secondaryFee; // if(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, creator, royaltyFee); // } // if (purchase.tokenStandard == TokenStandard.ERC721) { // IERC721(purchase.collection).safeTransferFrom(purchase.seller, msg.sender, purchase.tokenId); // } else { // 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, // purchase.tokenStandard // ); // } // } }
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":"error","name":"ReentrancyGuardReentrantCall","inputs":[]},{"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},{"type":"uint8","name":"tokenStandard","internalType":"enum NFTMarketplace.TokenStandard","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},{"type":"uint8","name":"tokenStandard","internalType":"enum NFTMarketplace.TokenStandard","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},{"type":"uint8","name":"tokenStandard","internalType":"enum NFTMarketplace.TokenStandard","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},{"type":"uint8","name":"tokenStandard","internalType":"enum NFTMarketplace.TokenStandard","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"},{"type":"uint8","name":"tokenStandard","internalType":"enum NFTMarketplace.TokenStandard"}],"name":"auctions","inputs":[{"type":"uint256","name":"","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":"uint8","name":"tokenStandard","internalType":"enum NFTMarketplace.TokenStandard"}]},{"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":"uint8","name":"tokenStandard","internalType":"enum NFTMarketplace.TokenStandard"}]},{"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"},{"type":"uint8","name":"tokenStandard","internalType":"enum NFTMarketplace.TokenStandard"}]}],"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"},{"type":"uint8","name":"tokenStandard","internalType":"enum NFTMarketplace.TokenStandard"}]}],"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":"uint8","name":"tokenStandard","internalType":"enum NFTMarketplace.TokenStandard"}]},{"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":"uint8","name":"tokenStandard","internalType":"enum NFTMarketplace.TokenStandard"}]},{"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"},{"type":"uint8","name":"tokenStandard","internalType":"enum NFTMarketplace.TokenStandard"}],"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":"uint8","name":"tokenStandard","internalType":"enum NFTMarketplace.TokenStandard"}]},{"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"},{"type":"uint8","name":"tokenStandard","internalType":"enum NFTMarketplace.TokenStandard"}],"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":"nonpayable","outputs":[{"type":"bytes4","name":"","internalType":"bytes4"}],"name":"onERC721Received","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"address","name":"","internalType":"address"},{"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":"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
0x60a06040523480156200001157600080fd5b506040516200628b3803806200628b8339810160408190526200003491620001e9565b33806200005c57604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b620000678162000199565b50600180556001600160a01b038316620000c45760405162461bcd60e51b815260206004820152601560248201527f496e76616c696420746f6b656e20616464726573730000000000000000000000604482015260640162000053565b6103e8821115620001185760405162461bcd60e51b815260206004820152601460248201527f5072696d6172792066656520746f6f2068696768000000000000000000000000604482015260640162000053565b6103e88111156200016c5760405162461bcd60e51b815260206004820152601660248201527f5365636f6e646172792066656520746f6f206869676800000000000000000000604482015260640162000053565b6001600160a01b03909216608052600255600355610e1060085562278d00600955610258600a556200022e565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600080600060608486031215620001ff57600080fd5b83516001600160a01b03811681146200021757600080fd5b602085015160409095015190969495509392505050565b608051615fdf620002ac600039600081816105cf01528181610da101528181610e3a01528181611c0d01528181611c8d01528181611f2901528181611fbc015281816126b901528181612e2701528181612ebb01528181612f550152818161380001528181613a0d01528181614e160152614eae0152615fdf6000f3fe608060405234801561001057600080fd5b50600436106102745760003560e01c806361d9db2d11610151578063a914607c116100c3578063d371f24f11610087578063d371f24f146106bc578063e3b43677146106e5578063ee533efb14610765578063ef706adf14610778578063f23a6e611461078b578063f2fde38b146107aa57600080fd5b8063a914607c1461065b578063aafa238114610664578063bc197c8114610677578063c815729d14610696578063cf25a2fd146106a957600080fd5b80637c89d2f0116101155780637c89d2f0146105ca57806382223202146105fe57806388b10c75146106115780638da5cb5b14610624578063922965b31461063557806396b5a7551461064857600080fd5b806361d9db2d146105265780636bd3a64b1461052f578063715018a6146105a657806371626bd9146105ae5780637561a71d146105c157600080fd5b806344328a69116101ea57806348eff1a6116101ae57806348eff1a61461044a578063541348761461045d578063570ff4de14610466578063571a26a01461046f57806357c90de51461050057806359edbe711461051357600080fd5b806344328a69146103e45780634579268a146103f757806347518c1614610419578063476343ee1461043957806348c9581e1461044157600080fd5b80631cd8d5121161023c5780631cd8d512146103315780632e9936111461034457806334277f07146103575780633f1ffcec1461037857806341c40576146103b157806342eb81d5146103c457600080fd5b806301ffc9a7146102795780630d8264c1146102a15780630f54a822146102c4578063150b7a02146102d95780631ba186ce14610310575b600080fd5b61028c61028736600461525f565b6107bd565b60405190151581526020015b60405180910390f35b61028c6102af36600461529e565b600c6020526000908152604090205460ff1681565b6102d76102d23660046152bb565b6107f4565b005b6102f76102e7366004615389565b630a85bd0160e11b949350505050565b6040516001600160e01b03199091168152602001610298565b61032361031e3660046153f4565b61086a565b60405161029892919061546d565b6102d761033f3660046152bb565b610ac2565b6102d76103523660046152bb565b610b28565b61036a6103653660046153f4565b611161565b60405161029892919061548f565b6103a36103863660046154d7565b600f60209081526000928352604080842090915290825290205481565b604051908152602001610298565b6102d76103bf36600461529e565b611183565b6103d76103d2366004615507565b61131b565b6040516102989190615529565b6102d76103f2366004615550565b61141f565b61040a6104053660046152bb565b61198d565b604051610298939291906155dc565b61042c61042736600461565c565b611ae5565b604051610298919061569e565b6102d7611beb565b6103a360095481565b6103a36104583660046156fc565b611d31565b6103a360085481565b6103a360035481565b6104e961047d3660046152bb565b600e602052600090815260409020805460018201546002830154600384015460048501546005860154600687015460078801546008909801546001600160a01b03978816989697959694959394929391929181169060ff600160a01b8204811691600160a81b9004168b565b6040516102989b9a99989796959493929190615761565b6102d761050e366004615507565b611d96565b6102d76105213660046157e3565b6120ef565b6103a360055481565b61059461053d36600461565c565b600b6020908152600093845260408085208252928452828420905282529020805460018201546002830154600384015460048501546005909501546001600160a01b03909416949293919260ff9182169290911686565b6040516102989695949392919061580f565b6102d7612408565b61036a6105bc3660046153f4565b61241c565b6103a360025481565b6105f17f000000000000000000000000000000000000000000000000000000000000000081565b604051610298919061585c565b6102d761060c3660046152bb565b612432565b6102d761061f3660046152bb565b6124b2565b6000546001600160a01b03166105f1565b61036a610643366004615550565b612788565b6102d76106563660046152bb565b6127ab565b6103a3600a5481565b6102d7610672366004615870565b612a9a565b6102f7610685366004615933565b63bc197c8160e01b95945050505050565b6102d76106a43660046152bb565b613252565b6004546105f1906001600160a01b031681565b6105f16106ca3660046152bb565b6010602052600090815260409020546001600160a01b031681565b6107526106f33660046153f4565b60116020908152600093845260408085208252928452828420905282529020805460018201546002830154600384015460048501546005909501546001600160a01b039485169593909416939192909160ff8082169161010090041687565b60405161029897969594939291906159e0565b6102d7610773366004615a35565b613361565b6102d76107863660046152bb565b6138f2565b6102f7610799366004615a98565b63f23a6e6160e01b95945050505050565b6102d76107b836600461529e565b613ad9565b60006001600160e01b03198216630271189760e51b14806107ee57506301ffc9a760e01b6001600160e01b03198316145b92915050565b6107fc613b14565b6103e88111156108275760405162461bcd60e51b815260040161081e90615b00565b60405180910390fd5b60038190556040805160008152602081018390527fdcabe98a3516480dd980e2164ecede5a6829fda8ff4471d83d8bf3391367815491015b60405180910390a150565b6060600080805b600554811015610927576000818152600d6020908152604091829020548251638da5cb5b60e01b815292516001600160a01b0391821693918b16928492638da5cb5b92600480830193928290030181865afa1580156108d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108f89190615b26565b6001600160a01b031603610914578261091081615b59565b9350505b508061091f81615b59565b915050610871565b50808511156109485760405162461bcd60e51b815260040161081e90615b72565b60006109548683615b9a565b9050848111156109615750835b806001600160401b03811115610979576109796152d4565b6040519080825280602002602001820160405280156109a2578160200160208202803683370190505b50935060008060005b600554811080156109bb57508383105b15610ab3576000818152600d6020908152604091829020548251638da5cb5b60e01b815292516001600160a01b0391821693918e16928492638da5cb5b92600480830193928290030181865afa158015610a19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a3d9190615b26565b6001600160a01b031603610a9f5789831015610a665782610a5d81615b59565b93505050610aa1565b80888581518110610a7957610a79615bad565b6001600160a01b039092166020928302919091019091015283610a9b81615b59565b9450505b505b80610aab81615b59565b9150506109ab565b50929350505050935093915050565b610aca613b14565b6103e8811115610aec5760405162461bcd60e51b815260040161081e90615b00565b60028190556040805160018152602081018390527fdcabe98a3516480dd980e2164ecede5a6829fda8ff4471d83d8bf33913678154910161085f565b610b30613b41565b6000818152600e60205260408120906008820154600160a01b900460ff166002811115610b5f57610b5f6155a2565b14610b7c5760405162461bcd60e51b815260040161081e90615bc3565b80600501544211610bc35760405162461bcd60e51b8152602060048201526011602482015270105d58dd1a5bdb881b9bdd08195b991959607a1b604482015260640161081e565b60088101546001600160a01b0316610c0e5760405162461bcd60e51b815260206004820152600e60248201526d139bc8189a591cc81c1b1858d95960921b604482015260640161081e565b600881018054600160a01b60ff60a01b1990911617905560008281526010602052604080822054600284015460068501549251636a4731c560e11b815260048101939093526001600160a01b03909116929091839063d48e638a90602401602060405180830381865afa158015610c89573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cad9190615b26565b6003548554919250906001600160a01b0390811690831603610cce57506002545b6000846001600160a01b03166359c8b7dd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d329190615bef565b905060006103e8610d438487615c13565b610d4d9190615c2a565b905060006103e8610d6261ffff851688615c13565b610d6c9190615c2a565b9050600081610d7b8489615b9a565b610d859190615b9a565b895460405163a9059cbb60e01b81529192506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081169263a9059cbb92610dd99216908590600401615c4c565b6020604051808303816000875af1158015610df8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e1c9190615c65565b508115610eb65760405163a9059cbb60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb90610e719089908690600401615c4c565b6020604051808303816000875af1158015610e90573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eb49190615c65565b505b600160088a0154600160a81b900460ff166001811115610ed857610ed86155a2565b03610f4f57600889015460068a0154604051632142170760e11b81526001600160a01b038b8116936342842e0e93610f1893309390921691600401615c87565b600060405180830381600087803b158015610f3257600080fd5b505af1158015610f46573d6000803e3d6000fd5b50505050610fc5565b600889015460068a015460078b0154604051637921219560e11b81526001600160a01b03808d169463f242432a94610f9294309492909316929091600401615cab565b600060405180830381600087803b158015610fac57600080fd5b505af1158015610fc0573d6000803e3d6000fd5b505050505b60008960000160009054906101000a90046001600160a01b03169050600b60008a6001600160a01b03166001600160a01b0316815260200190815260200160002060008b6006015481526020019081526020016000206000826001600160a01b03166001600160a01b03168152602001908152602001600020600080820160006101000a8154906001600160a01b030219169055600182016000905560028201600090556003820160006101000a81549060ff021916905560048201600090556005820160006101000a81549060ff021916905550508960060154896001600160a01b0316600080516020615f8a833981519152836040516110fd91906001600160a01b03919091168152604060208201819052600f908201526e105550d51253d397d4d15515131151608a1b606082015260800190565b60405180910390a360088a01546040518981526001600160a01b03909116908c907fc9f72b276a388619c6d185d146697036241880c36654b1a3ffdad07c24038d999060200160405180910390a35050505050505050505061115e60018055565b50565b6060600061117760008087878760026000613b6b565b91509150935093915050565b6004546001600160a01b031633146111d95760405162461bcd60e51b815260206004820152601960248201527827b7363c903330b1ba37b93c9031b0b7103932b3b4b9ba32b960391b604482015260640161081e565b6001600160a01b03811661122f5760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420636f6c6c656374696f6e2061646472657373000000000000604482015260640161081e565b6001600160a01b0381166000908152600c602052604090205460ff161561128d5760405162461bcd60e51b8152602060048201526012602482015271105b1c9958591e481c9959da5cdd195c995960721b604482015260640161081e565b6001600160a01b0381166000818152600c60209081526040808320805460ff19166001179055600580548452600d909252822080546001600160a01b031916909317909255815491906112df83615b59565b90915550506040516001600160a01b038216907ffb99393fd31547f4a765604f2c2d122ce8ccb313edeef8b951130d8bcca866e990600090a250565b606060055483111561133f5760405162461bcd60e51b815260040161081e90615b72565b60008360055461134f9190615b9a565b90508281111561135c5750815b806001600160401b03811115611374576113746152d4565b60405190808252806020026020018201604052801561139d578160200160208202803683370190505b50915060005b8181101561141757600d60006113b98388615ce3565b815260200190815260200160002060009054906101000a90046001600160a01b03168382815181106113ed576113ed615bad565b6001600160a01b03909216602092830291909101909101528061140f81615b59565b9150506113a3565b505092915050565b611427613b41565b6001600160a01b0385166000908152600c602052604090205460ff1661145f5760405162461bcd60e51b815260040161081e90615cf6565b6000831161147f5760405162461bcd60e51b815260040161081e90615d29565b6000821161149f5760405162461bcd60e51b815260040161081e90615d50565b60018160018111156114b3576114b36155a2565b0361167457816001146114d85760405162461bcd60e51b815260040161081e90615d7a565b6040516331a9108f60e11b81526004810185905233906001600160a01b03871690636352211e90602401602060405180830381865afa15801561151f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115439190615b26565b6001600160a01b0316146115695760405162461bcd60e51b815260040161081e90615dad565b60405163020604bf60e21b81526004810185905230906001600160a01b0387169063081812fc90602401602060405180830381865afa1580156115b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115d49190615b26565b6001600160a01b03161480611653575060405163e985e9c560e01b81526001600160a01b0386169063e985e9c5906116129033903090600401615dd6565b602060405180830381865afa15801561162f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116539190615c65565b61166f5760405162461bcd60e51b815260040161081e90615df0565b61178c565b604051627eeac760e11b815282906001600160a01b0387169062fdd58e906116a29033908990600401615c4c565b602060405180830381865afa1580156116bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116e39190615e16565b10156117015760405162461bcd60e51b815260040161081e90615e2f565b60405163e985e9c560e01b81526001600160a01b0386169063e985e9c59061172f9033903090600401615dd6565b602060405180830381865afa15801561174c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117709190615c65565b61178c5760405162461bcd60e51b815260040161081e90615df0565b6001600160a01b0385166000908152600b60209081526040808320878452825280832033845290915290206002810154158061181d57506001600382015460ff1660018111156117de576117de6155a2565b14801561181d5750600060048201546000908152600e6020526040902060080154600160a01b900460ff16600281111561181a5761181a6155a2565b14155b6118395760405162461bcd60e51b815260040161081e90615e5d565b6040805160c08101825233815260208101869052908101849052606081016000815260200160008152602001836001811115611877576118776155a2565b90526001600160a01b038781166000908152600b602090815260408083208a84528252808320338452825291829020845181546001600160a01b031916941693909317835583015160018084019190915590830151600283015560608301516003830180549192909160ff19169083818111156118f6576118f66155a2565b02179055506080820151600482015560a082015160058201805460ff191660018381811115611927576119276155a2565b021790555090505084866001600160a01b03167f24a1c41b19e085f48ac3aebb0b817e1076c3b1c5842d40a110da264537cbe800338787600080896040516119749695949392919061580f565b60405180910390a35061198660018055565b5050505050565b6040805160e08101825260008082526020808301829052828401829052606083018290526080830182905260a0830182905260c0830182905284825260139052918220546001600160a01b03169190826119f95760405162461bcd60e51b815260040161081e90615e85565b6000848152601460209081526040808320546001600160a01b038088168552601184528285208286528452828520898652845293829020825160e081018452815486168152600182015490951693850193909352600283015491840191909152600380830154606085015260048301546080850152600583015491955060a084019160ff1690811115611a8e57611a8e6155a2565b6003811115611a9f57611a9f6155a2565b81526020016005820160019054906101000a900460ff166001811115611ac757611ac76155a2565b6001811115611ad857611ad86155a2565b90525090505b9193909250565b611b1b6040805160c08101825260008082526020820181905291810182905260608101829052608081018290529060a082015290565b6001600160a01b038085166000908152600b6020908152604080832087845282528083208685168452825291829020825160c08101845281549094168452600180820154928501929092526002810154928401929092526003820154606084019160ff90911690811115611b9157611b916155a2565b6001811115611ba257611ba26155a2565b815260048201546020820152600582015460409091019060ff166001811115611bcd57611bcd6155a2565b6001811115611bde57611bde6155a2565b90525090505b9392505050565b611bf3613b14565b6040516370a0823160e01b81526000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190611c4290309060040161585c565b602060405180830381865afa158015611c5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c839190615e16565b9050801561115e577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb611ccc6000546001600160a01b031690565b836040518363ffffffff1660e01b8152600401611cea929190615c4c565b6020604051808303816000875af1158015611d09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d2d9190615c65565b5050565b6000611d3b613b41565b611d4a88888888888888613c29565b60068054906000611d5a83615b59565b9091555050600654611d7089898989858861410a565b611d80818a8a8a8a8a8a8a614254565b9050611d8b60018055565b979650505050505050565b611d9e613b41565b6000828152600e60205260408120906008820154600160a01b900460ff166002811115611dcd57611dcd6155a2565b14611dea5760405162461bcd60e51b815260040161081e90615bc3565b8060050154421115611e2e5760405162461bcd60e51b815260206004820152600d60248201526c105d58dd1a5bdb88195b991959609a1b604482015260640161081e565b80600301548160020154611e429190615ce3565b821015611e7f5760405162461bcd60e51b815260206004820152600b60248201526a42696420746f6f206c6f7760a81b604482015260640161081e565b600a54428260050154611e929190615b9a565b11611ee157600a54611ea49042615ce3565b6005820181905560405190815283907f6e912a3a9105bdd2af817ba5adc14e6c127c1035b5b648faa29ca0d58ab8ff4e9060200160405180910390a25b60088101546000848152600f602090815260408083206001600160a01b03909416808452939091529020548115611fa55760405163a9059cbb60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb90611f609085908590600401615c4c565b6020604051808303816000875af1158015611f7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fa39190615c65565b505b6040516323b872dd60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906323b872dd90611ff590339030908990600401615c87565b6020604051808303816000875af1158015612014573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120389190615c65565b6120765760405162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b604482015260640161081e565b6008830180546001600160a01b03191633908117909155600284018590556000868152600f60209081526040808320848452825291829020879055905186815287917f0e54eff26401bf69b81b26f60bd85ef47f5d85275c1d268d84f68d6897431c47910160405180910390a3505050611d2d60018055565b6120f7613b41565b6001600160a01b038083166000908152600b602090815260408083208584528252808320338085529252909120805490921614801561213a575060008160020154115b61217a5760405162461bcd60e51b81526020600482015260116024820152704e6f20616374697665206c697374696e6760781b604482015260640161081e565b6001600382015460ff166001811115612195576121956155a2565b0361234a5760048101546000908152600e60205260408120906008820154600160a01b900460ff1660028111156121ce576121ce6155a2565b146121eb5760405162461bcd60e51b815260040161081e90615bc3565b60088101546001600160a01b0316156122165760405162461bcd60e51b815260040161081e90615eb3565b60088101805460ff60a01b1916600160a11b179055600582015460019060ff1681811115612246576122466155a2565b036122b257604051632142170760e11b81526001600160a01b038516906342842e0e9061227b90309033908890600401615c87565b600060405180830381600087803b15801561229557600080fd5b505af11580156122a9573d6000803e3d6000fd5b5050505061231a565b6002820154604051637921219560e11b81526001600160a01b0386169163f242432a916122e791309133918991600401615cab565b600060405180830381600087803b15801561230157600080fd5b505af1158015612315573d6000803e3d6000fd5b505050505b60048201546040517f2809c7e17bf978fbc7194c0a694b638c4215e9140cacc6c38ca36010b45697df90600090a2505b6001600160a01b0383166000818152600b6020908152604080832086845282528083203380855290835281842080546001600160a01b0319168155600181018590556002810185905560038101805460ff19908116909155600482019590955560050180549094169093558051928352908201819052601190820152702922a6a7ab22a22fa12cafa9a2a62622a960791b6060820152839190600080516020615f8a8339815191529060800160405180910390a350611d2d60018055565b612410613b14565b61241a600061453e565b565b6060600061117760008087878760016000613b6b565b61243a613b14565b6000811161247d5760405162461bcd60e51b815260206004820152601060248201526f125b9d985b1a59081a5b9d195c9d985b60821b604482015260640161081e565b600a8190556040518181527f70d2c25f438b055a840aa5b6a9c16e5555b10f0b947ac750dbd16ecefd55e78f9060200161085f565b6124ba613b41565b6000818152601360209081526040808320546014909252909120546001600160a01b0390911690816124fe5760405162461bcd60e51b815260040161081e90615e85565b6001600160a01b03821660009081526011602090815260408083208484528252808320868452909152812090600582015460ff166003811115612543576125436155a2565b146125605760405162461bcd60e51b815260040161081e90615ee0565b60016005820154610100900460ff166001811115612580576125806155a2565b146125fb57604051627eeac760e11b81526000906001600160a01b0385169062fdd58e906125b49033908790600401615c4c565b602060405180830381865afa1580156125d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125f59190615e16565b11612671565b6040516331a9108f60e11b81526004810183905233906001600160a01b03851690636352211e90602401602060405180830381865afa158015612642573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126669190615b26565b6001600160a01b0316145b61268d5760405162461bcd60e51b815260040161081e90615dad565b6005810180546002919060ff191660018302179055508054600382015460028301546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081169363a9059cbb939116916126ee9190615c13565b6040518363ffffffff1660e01b815260040161270b929190615c4c565b6020604051808303816000875af115801561272a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061274e9190615c65565b50604051339085907f1b15bc319d6f29dd5bcf76cd2b89490ed2fe49f1a31fb6b8624b0029fd85c26590600090a350505061115e60018055565b6060600061279d878760008888600089613b6b565b915091509550959350505050565b6127b3613b41565b6000818152600e60205260408120906008820154600160a01b900460ff1660028111156127e2576127e26155a2565b146127ff5760405162461bcd60e51b815260040161081e90615bc3565b80546001600160a01b031633146128455760405162461bcd60e51b815260206004820152600a6024820152692737ba1039b2b63632b960b11b604482015260640161081e565b60088101546001600160a01b0316156128705760405162461bcd60e51b815260040161081e90615eb3565b60088101805460ff60a01b1916600160a11b17908190556000838152601060205260409020546001600160a01b031690600190600160a81b900460ff16818111156128bd576128bd6155a2565b036129315781546006830154604051632142170760e11b81526001600160a01b03848116936342842e0e936128fa93309390921691600401615c87565b600060405180830381600087803b15801561291457600080fd5b505af1158015612928573d6000803e3d6000fd5b505050506129a4565b815460068301546007840154604051637921219560e11b81526001600160a01b038086169463f242432a9461297194309492909316929091600401615cab565b600060405180830381600087803b15801561298b57600080fd5b505af115801561299f573d6000803e3d6000fd5b505050505b6001600160a01b038181166000818152600b602090815260408083206006880180548552908352818420885487168552835281842080546001600160a01b0319168155600181018590556002810185905560038101805460ff19908116909155600482019590955560050180549094169093559154865483519516855290840182905260118483015270105550d51253d397d0d05390d153131151607a1b606085015290519092600080516020615f8a833981519152919081900360800190a360405183907f2809c7e17bf978fbc7194c0a694b638c4215e9140cacc6c38ca36010b45697df90600090a2505061115e60018055565b612aa2613b41565b6001600160a01b0385166000908152600c602052604090205460ff16612ada5760405162461bcd60e51b815260040161081e90615cf6565b6001600160a01b038086166000908152600b60209081526040808320888452825280832087851680855292529091208054909216148015612b1f575060008160020154115b612b5d5760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206c697374696e6760881b604482015260640161081e565b6000600382015460ff166001811115612b7857612b786155a2565b14612bc15760405162461bcd60e51b81526020600482015260196024820152784e6f742061206669786564207072696365206c697374696e6760381b604482015260640161081e565b8281600201541015612c0d5760405162461bcd60e51b8152602060048201526015602482015274496e73756666696369656e74207175616e7469747960581b604482015260640161081e565b816001811115612c1f57612c1f6155a2565b600582015460ff166001811115612c3857612c386155a2565b14612c7f5760405162461bcd60e51b81526020600482015260176024820152760a8ded6cadc40e6e8c2dcc8c2e4c840dad2e6dac2e8c6d604b1b604482015260640161081e565b6001826001811115612c9357612c936155a2565b03612cb85782600114612cb85760405162461bcd60e51b815260040161081e90615d7a565b604051636a4731c560e11b8152600481018690526000906001600160a01b0388169063d48e638a90602401602060405180830381865afa158015612d00573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d249190615b26565b6003549091506001600160a01b0380871690831603612d4257506002545b6000886001600160a01b03166359c8b7dd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612d82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612da69190615bef565b90506000868560010154612dba9190615c13565b905060006103e8612dcb8584615c13565b612dd59190615c2a565b905060006103e8612dea61ffff861685615c13565b612df49190615c2a565b9050600081612e038486615b9a565b612e0d9190615b9a565b6040516323b872dd60e01b81529091506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906323b872dd90612e6090339030908890600401615c87565b6020604051808303816000875af1158015612e7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ea39190615c65565b506040516323b872dd60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906323b872dd90612ef49033908f908690600401615c87565b6020604051808303816000875af1158015612f13573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f379190615c65565b508115612fd3576040516323b872dd60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906323b872dd90612f8e9033908b908790600401615c87565b6020604051808303816000875af1158015612fad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fd19190615c65565b505b6001896001811115612fe757612fe76155a2565b03613053578c6001600160a01b03166342842e0e8c338f6040518463ffffffff1660e01b815260040161301c93929190615c87565b600060405180830381600087803b15801561303657600080fd5b505af115801561304a573d6000803e3d6000fd5b505050506130b8565b8c6001600160a01b031663f242432a8c338f8e6040518563ffffffff1660e01b81526004016130859493929190615cab565b600060405180830381600087803b15801561309f57600080fd5b505af11580156130b3573d6000803e3d6000fd5b505050505b898860020160008282546130cc9190615b9a565b909155505060028801546000036131f357600b60008e6001600160a01b03166001600160a01b0316815260200190815260200160002060008d815260200190815260200160002060008c6001600160a01b03166001600160a01b03168152602001908152602001600020600080820160006101000a8154906001600160a01b030219169055600182016000905560028201600090556003820160006101000a81549060ff021916905560048201600090556005820160006101000a81549060ff021916905550508b8d6001600160a01b0316600080516020615f8a8339815191528d6040516131ea91906001600160a01b039190911681526040602082018190526008908201526714d3d31117d3d55560c21b606082015260800190565b60405180910390a35b8b8d6001600160a01b03167f613c4fe987b07513b1ef1f1db273836f72146c711b322b46f8f611051d0ed6668d338c600101548f8f604051613239959493929190615f0e565b60405180910390a3505050505050505061198660018055565b61325a613b41565b60008060006132688461458e565b6040805160e08101825282546001600160a01b0390811682526001840154166020820152600283015491810191909152600380830154606083015260048301546080830152600583015494975092955090935060009261333692879287929091879160a084019160ff909116908111156132e4576132e46155a2565b60038111156132f5576132f56155a2565b81526020016005820160019054906101000a900460ff16600181111561331d5761331d6155a2565b600181111561332e5761332e6155a2565b905250614686565b905061334884848460030154846147db565b613354848484886149f9565b5050505061115e60018055565b613369613b41565b6001600160a01b0386166000908152600c602052604090205460ff166133a15760405162461bcd60e51b815260040161081e90615cf6565b600083116133c15760405162461bcd60e51b815260040161081e90615d50565b600082116133e15760405162461bcd60e51b815260040161081e90615d29565b6001600160a01b0384166134285760405162461bcd60e51b815260206004820152600e60248201526d24b73b30b634b21039b2b63632b960911b604482015260640161081e565b336001600160a01b0385160361347c5760405162461bcd60e51b815260206004820152601960248201527821b0b73737ba1036b0b5b29037b33332b9103a379039b2b63360391b604482015260640161081e565b6001816001811115613490576134906155a2565b0361357157826001146134b55760405162461bcd60e51b815260040161081e90615d7a565b6040516331a9108f60e11b8152600481018690526001600160a01b038086169190881690636352211e90602401602060405180830381865afa1580156134ff573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135239190615b26565b6001600160a01b03161461356c5760405162461bcd60e51b815260206004820152601060248201526f29b2b63632b9103737ba1037bbb732b960811b604482015260640161081e565b61362e565b604051627eeac760e11b815283906001600160a01b0388169062fdd58e9061359f9088908a90600401615c4c565b602060405180830381865afa1580156135bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135e09190615e16565b101561362e5760405162461bcd60e51b815260206004820152601b60248201527f496e73756666696369656e742073656c6c65722062616c616e63650000000000604482015260640161081e565b6007805490600061363e83615b59565b90915550506007546040805160e0810182523381526001600160a01b03871660208201529081018490526060810185905242608082015260a0810160008152602001836001811115613692576136926155a2565b90526001600160a01b0380891660009081526011602090815260408083208b84528252808320868452825291829020845181549085166001600160a01b0319918216178255918501516001808301805492909616919093161790935590830151600283015560608301516003808401919091556080840151600484015560a08401516005840180549193909260ff19909216918490811115613736576137366155a2565b021790555060c082015160058201805461ff001916610100836001811115613760576137606155a2565b021790555050336000818152601260209081526040808320805460018181018355918552838520018790556001600160a01b038b811685526015845282852080548084018255908652848620018890558d8116808652601685528386208e875285528386208054938401815586528486209092018890558785526013845282852080546001600160a01b03191690921790915560149092529091208990557f00000000000000000000000000000000000000000000000000000000000000001691506323b872dd90306138338888615c13565b6040518463ffffffff1660e01b815260040161385193929190615c87565b6020604051808303816000875af1158015613870573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138949190615c65565b5085876001600160a01b0316827f2f95efbf14694699c8a6ee93aea33c0b50ceb75a86d88934bb8772bb64f98a453389888a896040516138d8959493929190615f0e565b60405180910390a4506138ea60018055565b505050505050565b6138fa613b41565b6000818152601360209081526040808320546014909252909120546001600160a01b03909116908161393e5760405162461bcd60e51b815260040161081e90615e85565b6001600160a01b03808316600090815260116020908152604080832085845282528083208784529091529020805490911633146139b15760405162461bcd60e51b81526020600482015260116024820152702737ba1037b33332b91031b932b0ba37b960791b604482015260640161081e565b6000600582015460ff1660038111156139cc576139cc6155a2565b146139e95760405162461bcd60e51b815260040161081e90615ee0565b60058101805460ff1916600390811790915581015460028201546001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163a9059cbb913391613a3f91615c13565b6040518363ffffffff1660e01b8152600401613a5c929190615c4c565b6020604051808303816000875af1158015613a7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a9f9190615c65565b50604051339085907f1f51377b3e685a0e2419f9bb4ba7c07ec54936353ba3d0fb3c6538dab676622290600090a350505061115e60018055565b613ae1613b14565b6001600160a01b038116613b0b576000604051631e4fbdf760e01b815260040161081e919061585c565b61115e8161453e565b6000546001600160a01b0316331461241a573360405163118cdaa760e01b815260040161081e919061585c565b600260015403613b6457604051633ee5aeb560e01b815260040160405180910390fd5b6002600155565b60606000806040518060a001604052808b6001600160a01b031681526020018a8152602001896001600160a01b031681526020018660ff168152602001856001811115613bba57613bba6155a2565b905290506000613bcb898784614f73565b90506000613bd98284614ff4565b9050801580613be85750808910155b15613c085760408051600081526020810190915294509250613c1d915050565b613c1582848b8b85615056565b945094505050505b97509795505050505050565b6001600160a01b0387166000908152600c602052604090205460ff16613c615760405162461bcd60e51b815260040161081e90615cf6565b60008511613c815760405162461bcd60e51b815260040161081e90615d50565b60008411613cc75760405162461bcd60e51b8152602060048201526013602482015272496e76616c696420737461727420707269636560681b604482015260640161081e565b60008311613d135760405162461bcd60e51b8152602060048201526019602482015278125b9d985b1a59081b5a5b88189a59081a5b98dc995b595b9d603a1b604482015260640161081e565b6008548210158015613d2757506009548211155b613d665760405162461bcd60e51b815260206004820152601060248201526f24b73b30b634b210323ab930ba34b7b760811b604482015260640161081e565b6001816001811115613d7a57613d7a6155a2565b03613f3b5784600114613d9f5760405162461bcd60e51b815260040161081e90615d7a565b6040516331a9108f60e11b81526004810187905233906001600160a01b03891690636352211e90602401602060405180830381865afa158015613de6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e0a9190615b26565b6001600160a01b031614613e305760405162461bcd60e51b815260040161081e90615dad565b60405163020604bf60e21b81526004810187905230906001600160a01b0389169063081812fc90602401602060405180830381865afa158015613e77573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e9b9190615b26565b6001600160a01b03161480613f1a575060405163e985e9c560e01b81526001600160a01b0388169063e985e9c590613ed99033903090600401615dd6565b602060405180830381865afa158015613ef6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f1a9190615c65565b613f365760405162461bcd60e51b815260040161081e90615df0565b614053565b604051627eeac760e11b815285906001600160a01b0389169062fdd58e90613f699033908b90600401615c4c565b602060405180830381865afa158015613f86573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613faa9190615e16565b1015613fc85760405162461bcd60e51b815260040161081e90615e2f565b60405163e985e9c560e01b81526001600160a01b0388169063e985e9c590613ff69033903090600401615dd6565b602060405180830381865afa158015614013573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140379190615c65565b6140535760405162461bcd60e51b815260040161081e90615df0565b6001600160a01b0387166000908152600b6020908152604080832089845282528083203384529091529020600281015415806140e457506001600382015460ff1660018111156140a5576140a56155a2565b1480156140e45750600060048201546000908152600e6020526040902060080154600160a01b900460ff1660028111156140e1576140e16155a2565b14155b6141005760405162461bcd60e51b815260040161081e90615e5d565b5050505050505050565b6040805160c081018252338152602081018590529081018590526060810160018152602001838152602001826001811115614147576141476155a2565b90526001600160a01b038781166000908152600b602090815260408083208a84528252808320338452825291829020845181546001600160a01b031916941693909317835583015160018084019190915590830151600283015560608301516003830180549192909160ff19169083818111156141c6576141c66155a2565b02179055506080820151600482015560a082015160058201805460ff1916600183818111156141f7576141f76155a2565b021790555090505084866001600160a01b03167f24a1c41b19e085f48ac3aebb0b817e1076c3b1c5842d40a110da264537cbe800338688600188886040516142449695949392919061580f565b60405180910390a3505050505050565b4260006142618483615ce3565b9050604051806101600160405280336001600160a01b0316815260200187815260200187815260200186815260200183815260200182815260200189815260200188815260200160006001600160a01b03168152602001600060028111156142cb576142cb6155a2565b81526020018460018111156142e2576142e26155a2565b905260008b8152600e6020908152604091829020835181546001600160a01b03199081166001600160a01b0392831617835592850151600183015592840151600280830191909155606085015160038301556080850151600483015560a0850151600583015560c0850151600683015560e08501516007830155610100850151600883018054948516919095169081178555610120860151929492936001600160a81b0319161790600160a01b9084908111156143a1576143a16155a2565b021790555061014082015160088201805460ff60a81b1916600160a81b8360018111156143d0576143d06155a2565b0217905550505060008a815260106020526040902080546001600160a01b0319166001600160a01b038b161790556001836001811115614412576144126155a2565b0361447e57604051632142170760e11b81526001600160a01b038a16906342842e0e9061444790339030908d90600401615c87565b600060405180830381600087803b15801561446157600080fd5b505af1158015614475573d6000803e3d6000fd5b505050506144e3565b604051637921219560e11b81526001600160a01b038a169063f242432a906144b090339030908d908d90600401615cab565b600060405180830381600087803b1580156144ca57600080fd5b505af11580156144de573d6000803e3d6000fd5b505050505b87896001600160a01b03168b7f77445f9ade6cac698ef9dad2bdb9f4eb8cb6389e167068de61dc6bdd2458872b338a8a88888f8c60405161452a9796959493929190615f4d565b60405180910390a450505050505050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000818152601360205260408120546001600160a01b03169080826145c55760405162461bcd60e51b815260040161081e90615e85565b50506000828152601460209081526040808320546001600160a01b038516845260118352818420818552835281842086855290925282209091600582015460ff166003811115614617576146176155a2565b146146345760405162461bcd60e51b815260040161081e90615ee0565b60018101546001600160a01b03163314611ade5760405162461bcd60e51b8152602060048201526013602482015272139bdd081bd999995c881c9958da5c1a595b9d606a1b604482015260640161081e565b600060018260c0015160018111156146a0576146a06155a2565b0361473e576040516331a9108f60e11b81526004810184905233906001600160a01b03861690636352211e90602401602060405180830381865afa1580156146ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147109190615b26565b6001600160a01b0316146147365760405162461bcd60e51b815260040161081e90615dad565b506001611be4565b604051627eeac760e11b81526000906001600160a01b0386169062fdd58e9061476d9033908890600401615c4c565b602060405180830381865afa15801561478a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147ae9190615e16565b905082606001518110156147d45760405162461bcd60e51b815260040161081e90615e2f565b9050611be4565b6001600160a01b0384166000908152600b60209081526040808320868452825280832033845290915290206001600382015460ff166001811115614821576148216155a2565b0361489f57600060048201546000908152600e6020526040902060080154600160a01b900460ff16600281111561485a5761485a6155a2565b0361489f5760405162461bcd60e51b81526020600482015260156024820152744163746976652061756374696f6e2065786973747360581b604482015260640161081e565b600281015460006148b08285615b9a565b90506000858210156148c257816148c4565b855b905060006148d28288615b9a565b905080156149ee57838103614996576001600160a01b0389166000818152600b602090815260408083208c845282528083203380855290835281842080546001600160a01b0319168155600181018590556002810185905560038101805460ff19908116909155600482019590955560050180549094169093558051928352908201819052600d908201526c5a45524f5f5155414e5449545960981b6060820152899190600080516020615f8a8339815191529060800160405180910390a36149ee565b6149a08185615b9a565b6002860181905560405189916001600160a01b038c16917f36dba6da50cf7eb05d1a346c00f785d8a335ca42221245492e6e243624ce71fb916149e591339190615c4c565b60405180910390a35b505050505050505050565b60016005830154610100900460ff166001811115614a1957614a196155a2565b14614a925760405163e985e9c560e01b81526001600160a01b0385169063e985e9c590614a4c9033903090600401615dd6565b602060405180830381865afa158015614a69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614a8d9190615c65565b614b7c565b60405163020604bf60e21b81526004810184905230906001600160a01b0386169063081812fc90602401602060405180830381865afa158015614ad9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614afd9190615b26565b6001600160a01b03161480614b7c575060405163e985e9c560e01b81526001600160a01b0385169063e985e9c590614b3b9033903090600401615dd6565b602060405180830381865afa158015614b58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614b7c9190615c65565b614b985760405162461bcd60e51b815260040161081e90615df0565b604051636a4731c560e11b8152600481018490526000906001600160a01b0386169063d48e638a90602401602060405180830381865afa158015614be0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614c049190615b26565b600354909150336001600160a01b03831603614c1f57506002545b6000866001600160a01b03166359c8b7dd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614c5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614c839190615bef565b9050600085600301548660020154614c9b9190615c13565b905060006103e8614cac8584615c13565b614cb69190615c2a565b905060006103e8614ccb61ffff861685615c13565b614cd59190615c2a565b9050600081614ce48486615b9a565b614cee9190615b9a565b9050600160058a0154610100900460ff166001811115614d1057614d106155a2565b03614d7f578854604051632142170760e11b81526001600160a01b03808e16926342842e0e92614d4892339216908f90600401615c87565b600060405180830381600087803b158015614d6257600080fd5b505af1158015614d76573d6000803e3d6000fd5b50505050614dff565b8a6001600160a01b031663f242432a338b60000160009054906101000a90046001600160a01b03168d8d600301546040518563ffffffff1660e01b8152600401614dcc9493929190615cab565b600060405180830381600087803b158015614de657600080fd5b505af1158015614dfa573d6000803e3d6000fd5b505050505b60405163a9059cbb60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb90614e4d9033908590600401615c4c565b6020604051808303816000875af1158015614e6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614e909190615c65565b508115614f2a5760405163a9059cbb60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb90614ee5908a908690600401615c4c565b6020604051808303816000875af1158015614f04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614f289190615c65565b505b60058901805460ff19166001179055604051339089907fa7a40af5a1d0c10a3eb94af90cb008170915e8a71a6aaff052794cd762c72fc090600090a35050505050505050505050565b60008260ff16600003614fad575080516001600160a01b031660009081526016602090815260408083208285015184529091529020611be4565b8260ff16600103614fd657506001600160a01b0383166000908152601560205260409020611be4565b506001600160a01b0383166000908152601260205260409020611be4565b60008060005b845481101561504e5761502985828154811061501857615018615bad565b90600052602060002001548561516b565b1561503c578161503881615b59565b9250505b8061504681615b59565b915050614ffa565b509392505050565b60606000806150658685615b9a565b9050848111156150725750835b806001600160401b0381111561508a5761508a6152d4565b6040519080825280602002602001820160405280156150b3578160200160208202803683370190505b50925060008060005b8a54811080156150cb57508383105b1561515a5760008b82815481106150e4576150e4615bad565b906000526020600020015490506150fb818c61516b565b15615146578983101561511b578261511281615b59565b93505050615148565b80878561512781615b59565b96508151811061513957615139615bad565b6020026020010181815250505b505b8061515281615b59565b9150506150bc565b508593505050509550959350505050565b60008281526013602090815260408083205460148352818420546001600160a01b03909116808552601184528285208286528452828520878652909352908320606085015160ff1684036152075784516001600160a01b0384811691161480156151d85750846020015182145b80156151fd575060005b600582015460ff1660038111156151fb576151fb6155a2565b145b93505050506107ee565b846060015160ff1660010361523c57604085015160018201546001600160a01b0390811691161480156151fd575060006151e2565b604085015181546001600160a01b0390811691161480156151fd575060006151e2565b60006020828403121561527157600080fd5b81356001600160e01b031981168114611be457600080fd5b6001600160a01b038116811461115e57600080fd5b6000602082840312156152b057600080fd5b8135611be481615289565b6000602082840312156152cd57600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715615312576153126152d4565b604052919050565b600082601f83011261532b57600080fd5b81356001600160401b03811115615344576153446152d4565b615357601f8201601f19166020016152ea565b81815284602083860101111561536c57600080fd5b816020850160208301376000918101602001919091529392505050565b6000806000806080858703121561539f57600080fd5b84356153aa81615289565b935060208501356153ba81615289565b92506040850135915060608501356001600160401b038111156153dc57600080fd5b6153e88782880161531a565b91505092959194509250565b60008060006060848603121561540957600080fd5b833561541481615289565b95602085013595506040909401359392505050565b600081518084526020808501945080840160005b838110156154625781516001600160a01b03168752958201959082019060010161543d565b509495945050505050565b6040815260006154806040830185615429565b90508260208301529392505050565b604080825283519082018190526000906020906060840190828701845b828110156154c8578151845292840192908401906001016154ac565b50505092019290925292915050565b600080604083850312156154ea57600080fd5b8235915060208301356154fc81615289565b809150509250929050565b6000806040838503121561551a57600080fd5b50508035926020909101359150565b602081526000611be46020830184615429565b80356002811061554b57600080fd5b919050565b600080600080600060a0868803121561556857600080fd5b853561557381615289565b94506020860135935060408601359250606086013591506155966080870161553c565b90509295509295909350565b634e487b7160e01b600052602160045260246000fd5b600481106155c8576155c86155a2565b9052565b6002811061115e5761115e6155a2565b60006101208201905060018060a01b0380861683528460208401528084511660408401528060208501511660608401525060408301516080830152606083015160a0830152608083015160c083015260a083015161563d60e08401826155b8565b5060c083015161564c816155cc565b8061010084015250949350505050565b60008060006060848603121561567157600080fd5b833561567c81615289565b925060208401359150604084013561569381615289565b809150509250925092565b81516001600160a01b031681526020808301519082015260408083015190820152606082015160c08201906156d2816155cc565b60608301526080838101519083015260a08301516156ef816155cc565b8060a08401525092915050565b600080600080600080600060e0888a03121561571757600080fd5b873561572281615289565b96506020880135955060408801359450606088013593506080880135925060a0880135915061575360c0890161553c565b905092959891949750929550565b6001600160a01b038c81168252602082018c9052604082018b9052606082018a90526080820189905260a0820188905260c0820187905260e0820186905284166101008201526101608101600384106157bc576157bc6155a2565b836101208301526157cc836155cc565b826101408301529c9b505050505050505050505050565b600080604083850312156157f657600080fd5b823561580181615289565b946020939093013593505050565b6001600160a01b0387168152602081018690526040810185905260c08101615836856155cc565b84606083015283608083015261584b836155cc565b8260a0830152979650505050505050565b6001600160a01b0391909116815260200190565b600080600080600060a0868803121561588857600080fd5b853561589381615289565b94506020860135935060408601356158aa81615289565b9250606086013591506155966080870161553c565b600082601f8301126158d057600080fd5b813560206001600160401b038211156158eb576158eb6152d4565b8160051b6158fa8282016152ea565b928352848101820192828101908785111561591457600080fd5b83870192505b84831015611d8b5782358252918301919083019061591a565b600080600080600060a0868803121561594b57600080fd5b853561595681615289565b9450602086013561596681615289565b935060408601356001600160401b038082111561598257600080fd5b61598e89838a016158bf565b945060608801359150808211156159a457600080fd5b6159b089838a016158bf565b935060808801359150808211156159c657600080fd5b506159d38882890161531a565b9150509295509295909350565b6001600160a01b0388811682528716602082015260408101869052606081018590526080810184905260e08101615a1a60a08301856155b8565b615a23836155cc565b8260c083015298975050505050505050565b60008060008060008060c08789031215615a4e57600080fd5b8635615a5981615289565b9550602087013594506040870135615a7081615289565b93506060870135925060808701359150615a8c60a0880161553c565b90509295509295509295565b600080600080600060a08688031215615ab057600080fd5b8535615abb81615289565b94506020860135615acb81615289565b9350604086013592506060860135915060808601356001600160401b03811115615af457600080fd5b6159d38882890161531a565b6020808252600c908201526b08ccaca40e8dede40d0d2ced60a31b604082015260600190565b600060208284031215615b3857600080fd5b8151611be481615289565b634e487b7160e01b600052601160045260246000fd5b600060018201615b6b57615b6b615b43565b5060010190565b6020808252600e908201526d125b9d985b1a59081bd9999cd95d60921b604082015260600190565b818103818111156107ee576107ee615b43565b634e487b7160e01b600052603260045260246000fd5b60208082526012908201527141756374696f6e206e6f742061637469766560701b604082015260600190565b600060208284031215615c0157600080fd5b815161ffff81168114611be457600080fd5b80820281158282048414176107ee576107ee615b43565b600082615c4757634e487b7160e01b600052601260045260246000fd5b500490565b6001600160a01b03929092168252602082015260400190565b600060208284031215615c7757600080fd5b81518015158114611be457600080fd5b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b0394851681529290931660208301526040820152606081019190915260a06080820181905260009082015260c00190565b808201808211156107ee576107ee615b43565b60208082526019908201527810dbdb1b1958dd1a5bdb881b9bdd081c9959da5cdd195c9959603a1b604082015260600190565b6020808252600d908201526c496e76616c696420707269636560981b604082015260600190565b60208082526010908201526f496e76616c6964207175616e7469747960801b604082015260600190565b602080825260199082015278455243373231207175616e74697479206d757374206265203160381b604082015260600190565b6020808252600f908201526e2737ba103a37b5b2b71037bbb732b960891b604082015260600190565b6001600160a01b0392831681529116602082015260400190565b6020808252600c908201526b139bdd08185c1c1c9bdd995960a21b604082015260600190565b600060208284031215615e2857600080fd5b5051919050565b602080825260149082015273496e73756666696369656e742062616c616e636560601b604082015260600190565b6020808252600e908201526d105b1c9958591e481b1a5cdd195960921b604082015260600190565b60208082526014908201527313d999995c88191bd95cc81b9bdd08195e1a5cdd60621b604082015260600190565b602080825260139082015272109a591cc8185b1c9958591e481c1b1858d959606a1b604082015260600190565b602080825260149082015273496e76616c6964206f666665722073746174757360601b604082015260600190565b6001600160a01b03868116825285166020820152604081018490526060810183905260a08101615f3d836155cc565b8260808301529695505050505050565b6001600160a01b03881681526020810187905260408101869052606081018590526080810184905260a0810183905260e08101615a23836155cc56fe17d654f862f895d7741bf4e3234b08875e872e59e08d21c44d35187a60cfa2a2a2646970667358221220bc71d3d5b240b8e004a458e89c2348308d515d9a328fc4ba05dbc8418026ebc264736f6c63430008140033000000000000000000000000ad3e1f40ffe9318cd7b83b42d01a8c72fcbb8ca700000000000000000000000000000000000000000000000000000000000000190000000000000000000000000000000000000000000000000000000000000019
Deployed ByteCode
0x608060405234801561001057600080fd5b50600436106102745760003560e01c806361d9db2d11610151578063a914607c116100c3578063d371f24f11610087578063d371f24f146106bc578063e3b43677146106e5578063ee533efb14610765578063ef706adf14610778578063f23a6e611461078b578063f2fde38b146107aa57600080fd5b8063a914607c1461065b578063aafa238114610664578063bc197c8114610677578063c815729d14610696578063cf25a2fd146106a957600080fd5b80637c89d2f0116101155780637c89d2f0146105ca57806382223202146105fe57806388b10c75146106115780638da5cb5b14610624578063922965b31461063557806396b5a7551461064857600080fd5b806361d9db2d146105265780636bd3a64b1461052f578063715018a6146105a657806371626bd9146105ae5780637561a71d146105c157600080fd5b806344328a69116101ea57806348eff1a6116101ae57806348eff1a61461044a578063541348761461045d578063570ff4de14610466578063571a26a01461046f57806357c90de51461050057806359edbe711461051357600080fd5b806344328a69146103e45780634579268a146103f757806347518c1614610419578063476343ee1461043957806348c9581e1461044157600080fd5b80631cd8d5121161023c5780631cd8d512146103315780632e9936111461034457806334277f07146103575780633f1ffcec1461037857806341c40576146103b157806342eb81d5146103c457600080fd5b806301ffc9a7146102795780630d8264c1146102a15780630f54a822146102c4578063150b7a02146102d95780631ba186ce14610310575b600080fd5b61028c61028736600461525f565b6107bd565b60405190151581526020015b60405180910390f35b61028c6102af36600461529e565b600c6020526000908152604090205460ff1681565b6102d76102d23660046152bb565b6107f4565b005b6102f76102e7366004615389565b630a85bd0160e11b949350505050565b6040516001600160e01b03199091168152602001610298565b61032361031e3660046153f4565b61086a565b60405161029892919061546d565b6102d761033f3660046152bb565b610ac2565b6102d76103523660046152bb565b610b28565b61036a6103653660046153f4565b611161565b60405161029892919061548f565b6103a36103863660046154d7565b600f60209081526000928352604080842090915290825290205481565b604051908152602001610298565b6102d76103bf36600461529e565b611183565b6103d76103d2366004615507565b61131b565b6040516102989190615529565b6102d76103f2366004615550565b61141f565b61040a6104053660046152bb565b61198d565b604051610298939291906155dc565b61042c61042736600461565c565b611ae5565b604051610298919061569e565b6102d7611beb565b6103a360095481565b6103a36104583660046156fc565b611d31565b6103a360085481565b6103a360035481565b6104e961047d3660046152bb565b600e602052600090815260409020805460018201546002830154600384015460048501546005860154600687015460078801546008909801546001600160a01b03978816989697959694959394929391929181169060ff600160a01b8204811691600160a81b9004168b565b6040516102989b9a99989796959493929190615761565b6102d761050e366004615507565b611d96565b6102d76105213660046157e3565b6120ef565b6103a360055481565b61059461053d36600461565c565b600b6020908152600093845260408085208252928452828420905282529020805460018201546002830154600384015460048501546005909501546001600160a01b03909416949293919260ff9182169290911686565b6040516102989695949392919061580f565b6102d7612408565b61036a6105bc3660046153f4565b61241c565b6103a360025481565b6105f17f000000000000000000000000ad3e1f40ffe9318cd7b83b42d01a8c72fcbb8ca781565b604051610298919061585c565b6102d761060c3660046152bb565b612432565b6102d761061f3660046152bb565b6124b2565b6000546001600160a01b03166105f1565b61036a610643366004615550565b612788565b6102d76106563660046152bb565b6127ab565b6103a3600a5481565b6102d7610672366004615870565b612a9a565b6102f7610685366004615933565b63bc197c8160e01b95945050505050565b6102d76106a43660046152bb565b613252565b6004546105f1906001600160a01b031681565b6105f16106ca3660046152bb565b6010602052600090815260409020546001600160a01b031681565b6107526106f33660046153f4565b60116020908152600093845260408085208252928452828420905282529020805460018201546002830154600384015460048501546005909501546001600160a01b039485169593909416939192909160ff8082169161010090041687565b60405161029897969594939291906159e0565b6102d7610773366004615a35565b613361565b6102d76107863660046152bb565b6138f2565b6102f7610799366004615a98565b63f23a6e6160e01b95945050505050565b6102d76107b836600461529e565b613ad9565b60006001600160e01b03198216630271189760e51b14806107ee57506301ffc9a760e01b6001600160e01b03198316145b92915050565b6107fc613b14565b6103e88111156108275760405162461bcd60e51b815260040161081e90615b00565b60405180910390fd5b60038190556040805160008152602081018390527fdcabe98a3516480dd980e2164ecede5a6829fda8ff4471d83d8bf3391367815491015b60405180910390a150565b6060600080805b600554811015610927576000818152600d6020908152604091829020548251638da5cb5b60e01b815292516001600160a01b0391821693918b16928492638da5cb5b92600480830193928290030181865afa1580156108d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108f89190615b26565b6001600160a01b031603610914578261091081615b59565b9350505b508061091f81615b59565b915050610871565b50808511156109485760405162461bcd60e51b815260040161081e90615b72565b60006109548683615b9a565b9050848111156109615750835b806001600160401b03811115610979576109796152d4565b6040519080825280602002602001820160405280156109a2578160200160208202803683370190505b50935060008060005b600554811080156109bb57508383105b15610ab3576000818152600d6020908152604091829020548251638da5cb5b60e01b815292516001600160a01b0391821693918e16928492638da5cb5b92600480830193928290030181865afa158015610a19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a3d9190615b26565b6001600160a01b031603610a9f5789831015610a665782610a5d81615b59565b93505050610aa1565b80888581518110610a7957610a79615bad565b6001600160a01b039092166020928302919091019091015283610a9b81615b59565b9450505b505b80610aab81615b59565b9150506109ab565b50929350505050935093915050565b610aca613b14565b6103e8811115610aec5760405162461bcd60e51b815260040161081e90615b00565b60028190556040805160018152602081018390527fdcabe98a3516480dd980e2164ecede5a6829fda8ff4471d83d8bf33913678154910161085f565b610b30613b41565b6000818152600e60205260408120906008820154600160a01b900460ff166002811115610b5f57610b5f6155a2565b14610b7c5760405162461bcd60e51b815260040161081e90615bc3565b80600501544211610bc35760405162461bcd60e51b8152602060048201526011602482015270105d58dd1a5bdb881b9bdd08195b991959607a1b604482015260640161081e565b60088101546001600160a01b0316610c0e5760405162461bcd60e51b815260206004820152600e60248201526d139bc8189a591cc81c1b1858d95960921b604482015260640161081e565b600881018054600160a01b60ff60a01b1990911617905560008281526010602052604080822054600284015460068501549251636a4731c560e11b815260048101939093526001600160a01b03909116929091839063d48e638a90602401602060405180830381865afa158015610c89573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cad9190615b26565b6003548554919250906001600160a01b0390811690831603610cce57506002545b6000846001600160a01b03166359c8b7dd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d329190615bef565b905060006103e8610d438487615c13565b610d4d9190615c2a565b905060006103e8610d6261ffff851688615c13565b610d6c9190615c2a565b9050600081610d7b8489615b9a565b610d859190615b9a565b895460405163a9059cbb60e01b81529192506001600160a01b037f000000000000000000000000ad3e1f40ffe9318cd7b83b42d01a8c72fcbb8ca781169263a9059cbb92610dd99216908590600401615c4c565b6020604051808303816000875af1158015610df8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e1c9190615c65565b508115610eb65760405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000ad3e1f40ffe9318cd7b83b42d01a8c72fcbb8ca7169063a9059cbb90610e719089908690600401615c4c565b6020604051808303816000875af1158015610e90573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eb49190615c65565b505b600160088a0154600160a81b900460ff166001811115610ed857610ed86155a2565b03610f4f57600889015460068a0154604051632142170760e11b81526001600160a01b038b8116936342842e0e93610f1893309390921691600401615c87565b600060405180830381600087803b158015610f3257600080fd5b505af1158015610f46573d6000803e3d6000fd5b50505050610fc5565b600889015460068a015460078b0154604051637921219560e11b81526001600160a01b03808d169463f242432a94610f9294309492909316929091600401615cab565b600060405180830381600087803b158015610fac57600080fd5b505af1158015610fc0573d6000803e3d6000fd5b505050505b60008960000160009054906101000a90046001600160a01b03169050600b60008a6001600160a01b03166001600160a01b0316815260200190815260200160002060008b6006015481526020019081526020016000206000826001600160a01b03166001600160a01b03168152602001908152602001600020600080820160006101000a8154906001600160a01b030219169055600182016000905560028201600090556003820160006101000a81549060ff021916905560048201600090556005820160006101000a81549060ff021916905550508960060154896001600160a01b0316600080516020615f8a833981519152836040516110fd91906001600160a01b03919091168152604060208201819052600f908201526e105550d51253d397d4d15515131151608a1b606082015260800190565b60405180910390a360088a01546040518981526001600160a01b03909116908c907fc9f72b276a388619c6d185d146697036241880c36654b1a3ffdad07c24038d999060200160405180910390a35050505050505050505061115e60018055565b50565b6060600061117760008087878760026000613b6b565b91509150935093915050565b6004546001600160a01b031633146111d95760405162461bcd60e51b815260206004820152601960248201527827b7363c903330b1ba37b93c9031b0b7103932b3b4b9ba32b960391b604482015260640161081e565b6001600160a01b03811661122f5760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420636f6c6c656374696f6e2061646472657373000000000000604482015260640161081e565b6001600160a01b0381166000908152600c602052604090205460ff161561128d5760405162461bcd60e51b8152602060048201526012602482015271105b1c9958591e481c9959da5cdd195c995960721b604482015260640161081e565b6001600160a01b0381166000818152600c60209081526040808320805460ff19166001179055600580548452600d909252822080546001600160a01b031916909317909255815491906112df83615b59565b90915550506040516001600160a01b038216907ffb99393fd31547f4a765604f2c2d122ce8ccb313edeef8b951130d8bcca866e990600090a250565b606060055483111561133f5760405162461bcd60e51b815260040161081e90615b72565b60008360055461134f9190615b9a565b90508281111561135c5750815b806001600160401b03811115611374576113746152d4565b60405190808252806020026020018201604052801561139d578160200160208202803683370190505b50915060005b8181101561141757600d60006113b98388615ce3565b815260200190815260200160002060009054906101000a90046001600160a01b03168382815181106113ed576113ed615bad565b6001600160a01b03909216602092830291909101909101528061140f81615b59565b9150506113a3565b505092915050565b611427613b41565b6001600160a01b0385166000908152600c602052604090205460ff1661145f5760405162461bcd60e51b815260040161081e90615cf6565b6000831161147f5760405162461bcd60e51b815260040161081e90615d29565b6000821161149f5760405162461bcd60e51b815260040161081e90615d50565b60018160018111156114b3576114b36155a2565b0361167457816001146114d85760405162461bcd60e51b815260040161081e90615d7a565b6040516331a9108f60e11b81526004810185905233906001600160a01b03871690636352211e90602401602060405180830381865afa15801561151f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115439190615b26565b6001600160a01b0316146115695760405162461bcd60e51b815260040161081e90615dad565b60405163020604bf60e21b81526004810185905230906001600160a01b0387169063081812fc90602401602060405180830381865afa1580156115b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115d49190615b26565b6001600160a01b03161480611653575060405163e985e9c560e01b81526001600160a01b0386169063e985e9c5906116129033903090600401615dd6565b602060405180830381865afa15801561162f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116539190615c65565b61166f5760405162461bcd60e51b815260040161081e90615df0565b61178c565b604051627eeac760e11b815282906001600160a01b0387169062fdd58e906116a29033908990600401615c4c565b602060405180830381865afa1580156116bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116e39190615e16565b10156117015760405162461bcd60e51b815260040161081e90615e2f565b60405163e985e9c560e01b81526001600160a01b0386169063e985e9c59061172f9033903090600401615dd6565b602060405180830381865afa15801561174c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117709190615c65565b61178c5760405162461bcd60e51b815260040161081e90615df0565b6001600160a01b0385166000908152600b60209081526040808320878452825280832033845290915290206002810154158061181d57506001600382015460ff1660018111156117de576117de6155a2565b14801561181d5750600060048201546000908152600e6020526040902060080154600160a01b900460ff16600281111561181a5761181a6155a2565b14155b6118395760405162461bcd60e51b815260040161081e90615e5d565b6040805160c08101825233815260208101869052908101849052606081016000815260200160008152602001836001811115611877576118776155a2565b90526001600160a01b038781166000908152600b602090815260408083208a84528252808320338452825291829020845181546001600160a01b031916941693909317835583015160018084019190915590830151600283015560608301516003830180549192909160ff19169083818111156118f6576118f66155a2565b02179055506080820151600482015560a082015160058201805460ff191660018381811115611927576119276155a2565b021790555090505084866001600160a01b03167f24a1c41b19e085f48ac3aebb0b817e1076c3b1c5842d40a110da264537cbe800338787600080896040516119749695949392919061580f565b60405180910390a35061198660018055565b5050505050565b6040805160e08101825260008082526020808301829052828401829052606083018290526080830182905260a0830182905260c0830182905284825260139052918220546001600160a01b03169190826119f95760405162461bcd60e51b815260040161081e90615e85565b6000848152601460209081526040808320546001600160a01b038088168552601184528285208286528452828520898652845293829020825160e081018452815486168152600182015490951693850193909352600283015491840191909152600380830154606085015260048301546080850152600583015491955060a084019160ff1690811115611a8e57611a8e6155a2565b6003811115611a9f57611a9f6155a2565b81526020016005820160019054906101000a900460ff166001811115611ac757611ac76155a2565b6001811115611ad857611ad86155a2565b90525090505b9193909250565b611b1b6040805160c08101825260008082526020820181905291810182905260608101829052608081018290529060a082015290565b6001600160a01b038085166000908152600b6020908152604080832087845282528083208685168452825291829020825160c08101845281549094168452600180820154928501929092526002810154928401929092526003820154606084019160ff90911690811115611b9157611b916155a2565b6001811115611ba257611ba26155a2565b815260048201546020820152600582015460409091019060ff166001811115611bcd57611bcd6155a2565b6001811115611bde57611bde6155a2565b90525090505b9392505050565b611bf3613b14565b6040516370a0823160e01b81526000906001600160a01b037f000000000000000000000000ad3e1f40ffe9318cd7b83b42d01a8c72fcbb8ca716906370a0823190611c4290309060040161585c565b602060405180830381865afa158015611c5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c839190615e16565b9050801561115e577f000000000000000000000000ad3e1f40ffe9318cd7b83b42d01a8c72fcbb8ca76001600160a01b031663a9059cbb611ccc6000546001600160a01b031690565b836040518363ffffffff1660e01b8152600401611cea929190615c4c565b6020604051808303816000875af1158015611d09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d2d9190615c65565b5050565b6000611d3b613b41565b611d4a88888888888888613c29565b60068054906000611d5a83615b59565b9091555050600654611d7089898989858861410a565b611d80818a8a8a8a8a8a8a614254565b9050611d8b60018055565b979650505050505050565b611d9e613b41565b6000828152600e60205260408120906008820154600160a01b900460ff166002811115611dcd57611dcd6155a2565b14611dea5760405162461bcd60e51b815260040161081e90615bc3565b8060050154421115611e2e5760405162461bcd60e51b815260206004820152600d60248201526c105d58dd1a5bdb88195b991959609a1b604482015260640161081e565b80600301548160020154611e429190615ce3565b821015611e7f5760405162461bcd60e51b815260206004820152600b60248201526a42696420746f6f206c6f7760a81b604482015260640161081e565b600a54428260050154611e929190615b9a565b11611ee157600a54611ea49042615ce3565b6005820181905560405190815283907f6e912a3a9105bdd2af817ba5adc14e6c127c1035b5b648faa29ca0d58ab8ff4e9060200160405180910390a25b60088101546000848152600f602090815260408083206001600160a01b03909416808452939091529020548115611fa55760405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000ad3e1f40ffe9318cd7b83b42d01a8c72fcbb8ca7169063a9059cbb90611f609085908590600401615c4c565b6020604051808303816000875af1158015611f7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fa39190615c65565b505b6040516323b872dd60e01b81526001600160a01b037f000000000000000000000000ad3e1f40ffe9318cd7b83b42d01a8c72fcbb8ca716906323b872dd90611ff590339030908990600401615c87565b6020604051808303816000875af1158015612014573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120389190615c65565b6120765760405162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b604482015260640161081e565b6008830180546001600160a01b03191633908117909155600284018590556000868152600f60209081526040808320848452825291829020879055905186815287917f0e54eff26401bf69b81b26f60bd85ef47f5d85275c1d268d84f68d6897431c47910160405180910390a3505050611d2d60018055565b6120f7613b41565b6001600160a01b038083166000908152600b602090815260408083208584528252808320338085529252909120805490921614801561213a575060008160020154115b61217a5760405162461bcd60e51b81526020600482015260116024820152704e6f20616374697665206c697374696e6760781b604482015260640161081e565b6001600382015460ff166001811115612195576121956155a2565b0361234a5760048101546000908152600e60205260408120906008820154600160a01b900460ff1660028111156121ce576121ce6155a2565b146121eb5760405162461bcd60e51b815260040161081e90615bc3565b60088101546001600160a01b0316156122165760405162461bcd60e51b815260040161081e90615eb3565b60088101805460ff60a01b1916600160a11b179055600582015460019060ff1681811115612246576122466155a2565b036122b257604051632142170760e11b81526001600160a01b038516906342842e0e9061227b90309033908890600401615c87565b600060405180830381600087803b15801561229557600080fd5b505af11580156122a9573d6000803e3d6000fd5b5050505061231a565b6002820154604051637921219560e11b81526001600160a01b0386169163f242432a916122e791309133918991600401615cab565b600060405180830381600087803b15801561230157600080fd5b505af1158015612315573d6000803e3d6000fd5b505050505b60048201546040517f2809c7e17bf978fbc7194c0a694b638c4215e9140cacc6c38ca36010b45697df90600090a2505b6001600160a01b0383166000818152600b6020908152604080832086845282528083203380855290835281842080546001600160a01b0319168155600181018590556002810185905560038101805460ff19908116909155600482019590955560050180549094169093558051928352908201819052601190820152702922a6a7ab22a22fa12cafa9a2a62622a960791b6060820152839190600080516020615f8a8339815191529060800160405180910390a350611d2d60018055565b612410613b14565b61241a600061453e565b565b6060600061117760008087878760016000613b6b565b61243a613b14565b6000811161247d5760405162461bcd60e51b815260206004820152601060248201526f125b9d985b1a59081a5b9d195c9d985b60821b604482015260640161081e565b600a8190556040518181527f70d2c25f438b055a840aa5b6a9c16e5555b10f0b947ac750dbd16ecefd55e78f9060200161085f565b6124ba613b41565b6000818152601360209081526040808320546014909252909120546001600160a01b0390911690816124fe5760405162461bcd60e51b815260040161081e90615e85565b6001600160a01b03821660009081526011602090815260408083208484528252808320868452909152812090600582015460ff166003811115612543576125436155a2565b146125605760405162461bcd60e51b815260040161081e90615ee0565b60016005820154610100900460ff166001811115612580576125806155a2565b146125fb57604051627eeac760e11b81526000906001600160a01b0385169062fdd58e906125b49033908790600401615c4c565b602060405180830381865afa1580156125d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125f59190615e16565b11612671565b6040516331a9108f60e11b81526004810183905233906001600160a01b03851690636352211e90602401602060405180830381865afa158015612642573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126669190615b26565b6001600160a01b0316145b61268d5760405162461bcd60e51b815260040161081e90615dad565b6005810180546002919060ff191660018302179055508054600382015460028301546001600160a01b037f000000000000000000000000ad3e1f40ffe9318cd7b83b42d01a8c72fcbb8ca781169363a9059cbb939116916126ee9190615c13565b6040518363ffffffff1660e01b815260040161270b929190615c4c565b6020604051808303816000875af115801561272a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061274e9190615c65565b50604051339085907f1b15bc319d6f29dd5bcf76cd2b89490ed2fe49f1a31fb6b8624b0029fd85c26590600090a350505061115e60018055565b6060600061279d878760008888600089613b6b565b915091509550959350505050565b6127b3613b41565b6000818152600e60205260408120906008820154600160a01b900460ff1660028111156127e2576127e26155a2565b146127ff5760405162461bcd60e51b815260040161081e90615bc3565b80546001600160a01b031633146128455760405162461bcd60e51b815260206004820152600a6024820152692737ba1039b2b63632b960b11b604482015260640161081e565b60088101546001600160a01b0316156128705760405162461bcd60e51b815260040161081e90615eb3565b60088101805460ff60a01b1916600160a11b17908190556000838152601060205260409020546001600160a01b031690600190600160a81b900460ff16818111156128bd576128bd6155a2565b036129315781546006830154604051632142170760e11b81526001600160a01b03848116936342842e0e936128fa93309390921691600401615c87565b600060405180830381600087803b15801561291457600080fd5b505af1158015612928573d6000803e3d6000fd5b505050506129a4565b815460068301546007840154604051637921219560e11b81526001600160a01b038086169463f242432a9461297194309492909316929091600401615cab565b600060405180830381600087803b15801561298b57600080fd5b505af115801561299f573d6000803e3d6000fd5b505050505b6001600160a01b038181166000818152600b602090815260408083206006880180548552908352818420885487168552835281842080546001600160a01b0319168155600181018590556002810185905560038101805460ff19908116909155600482019590955560050180549094169093559154865483519516855290840182905260118483015270105550d51253d397d0d05390d153131151607a1b606085015290519092600080516020615f8a833981519152919081900360800190a360405183907f2809c7e17bf978fbc7194c0a694b638c4215e9140cacc6c38ca36010b45697df90600090a2505061115e60018055565b612aa2613b41565b6001600160a01b0385166000908152600c602052604090205460ff16612ada5760405162461bcd60e51b815260040161081e90615cf6565b6001600160a01b038086166000908152600b60209081526040808320888452825280832087851680855292529091208054909216148015612b1f575060008160020154115b612b5d5760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206c697374696e6760881b604482015260640161081e565b6000600382015460ff166001811115612b7857612b786155a2565b14612bc15760405162461bcd60e51b81526020600482015260196024820152784e6f742061206669786564207072696365206c697374696e6760381b604482015260640161081e565b8281600201541015612c0d5760405162461bcd60e51b8152602060048201526015602482015274496e73756666696369656e74207175616e7469747960581b604482015260640161081e565b816001811115612c1f57612c1f6155a2565b600582015460ff166001811115612c3857612c386155a2565b14612c7f5760405162461bcd60e51b81526020600482015260176024820152760a8ded6cadc40e6e8c2dcc8c2e4c840dad2e6dac2e8c6d604b1b604482015260640161081e565b6001826001811115612c9357612c936155a2565b03612cb85782600114612cb85760405162461bcd60e51b815260040161081e90615d7a565b604051636a4731c560e11b8152600481018690526000906001600160a01b0388169063d48e638a90602401602060405180830381865afa158015612d00573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d249190615b26565b6003549091506001600160a01b0380871690831603612d4257506002545b6000886001600160a01b03166359c8b7dd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612d82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612da69190615bef565b90506000868560010154612dba9190615c13565b905060006103e8612dcb8584615c13565b612dd59190615c2a565b905060006103e8612dea61ffff861685615c13565b612df49190615c2a565b9050600081612e038486615b9a565b612e0d9190615b9a565b6040516323b872dd60e01b81529091506001600160a01b037f000000000000000000000000ad3e1f40ffe9318cd7b83b42d01a8c72fcbb8ca716906323b872dd90612e6090339030908890600401615c87565b6020604051808303816000875af1158015612e7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ea39190615c65565b506040516323b872dd60e01b81526001600160a01b037f000000000000000000000000ad3e1f40ffe9318cd7b83b42d01a8c72fcbb8ca716906323b872dd90612ef49033908f908690600401615c87565b6020604051808303816000875af1158015612f13573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f379190615c65565b508115612fd3576040516323b872dd60e01b81526001600160a01b037f000000000000000000000000ad3e1f40ffe9318cd7b83b42d01a8c72fcbb8ca716906323b872dd90612f8e9033908b908790600401615c87565b6020604051808303816000875af1158015612fad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fd19190615c65565b505b6001896001811115612fe757612fe76155a2565b03613053578c6001600160a01b03166342842e0e8c338f6040518463ffffffff1660e01b815260040161301c93929190615c87565b600060405180830381600087803b15801561303657600080fd5b505af115801561304a573d6000803e3d6000fd5b505050506130b8565b8c6001600160a01b031663f242432a8c338f8e6040518563ffffffff1660e01b81526004016130859493929190615cab565b600060405180830381600087803b15801561309f57600080fd5b505af11580156130b3573d6000803e3d6000fd5b505050505b898860020160008282546130cc9190615b9a565b909155505060028801546000036131f357600b60008e6001600160a01b03166001600160a01b0316815260200190815260200160002060008d815260200190815260200160002060008c6001600160a01b03166001600160a01b03168152602001908152602001600020600080820160006101000a8154906001600160a01b030219169055600182016000905560028201600090556003820160006101000a81549060ff021916905560048201600090556005820160006101000a81549060ff021916905550508b8d6001600160a01b0316600080516020615f8a8339815191528d6040516131ea91906001600160a01b039190911681526040602082018190526008908201526714d3d31117d3d55560c21b606082015260800190565b60405180910390a35b8b8d6001600160a01b03167f613c4fe987b07513b1ef1f1db273836f72146c711b322b46f8f611051d0ed6668d338c600101548f8f604051613239959493929190615f0e565b60405180910390a3505050505050505061198660018055565b61325a613b41565b60008060006132688461458e565b6040805160e08101825282546001600160a01b0390811682526001840154166020820152600283015491810191909152600380830154606083015260048301546080830152600583015494975092955090935060009261333692879287929091879160a084019160ff909116908111156132e4576132e46155a2565b60038111156132f5576132f56155a2565b81526020016005820160019054906101000a900460ff16600181111561331d5761331d6155a2565b600181111561332e5761332e6155a2565b905250614686565b905061334884848460030154846147db565b613354848484886149f9565b5050505061115e60018055565b613369613b41565b6001600160a01b0386166000908152600c602052604090205460ff166133a15760405162461bcd60e51b815260040161081e90615cf6565b600083116133c15760405162461bcd60e51b815260040161081e90615d50565b600082116133e15760405162461bcd60e51b815260040161081e90615d29565b6001600160a01b0384166134285760405162461bcd60e51b815260206004820152600e60248201526d24b73b30b634b21039b2b63632b960911b604482015260640161081e565b336001600160a01b0385160361347c5760405162461bcd60e51b815260206004820152601960248201527821b0b73737ba1036b0b5b29037b33332b9103a379039b2b63360391b604482015260640161081e565b6001816001811115613490576134906155a2565b0361357157826001146134b55760405162461bcd60e51b815260040161081e90615d7a565b6040516331a9108f60e11b8152600481018690526001600160a01b038086169190881690636352211e90602401602060405180830381865afa1580156134ff573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135239190615b26565b6001600160a01b03161461356c5760405162461bcd60e51b815260206004820152601060248201526f29b2b63632b9103737ba1037bbb732b960811b604482015260640161081e565b61362e565b604051627eeac760e11b815283906001600160a01b0388169062fdd58e9061359f9088908a90600401615c4c565b602060405180830381865afa1580156135bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135e09190615e16565b101561362e5760405162461bcd60e51b815260206004820152601b60248201527f496e73756666696369656e742073656c6c65722062616c616e63650000000000604482015260640161081e565b6007805490600061363e83615b59565b90915550506007546040805160e0810182523381526001600160a01b03871660208201529081018490526060810185905242608082015260a0810160008152602001836001811115613692576136926155a2565b90526001600160a01b0380891660009081526011602090815260408083208b84528252808320868452825291829020845181549085166001600160a01b0319918216178255918501516001808301805492909616919093161790935590830151600283015560608301516003808401919091556080840151600484015560a08401516005840180549193909260ff19909216918490811115613736576137366155a2565b021790555060c082015160058201805461ff001916610100836001811115613760576137606155a2565b021790555050336000818152601260209081526040808320805460018181018355918552838520018790556001600160a01b038b811685526015845282852080548084018255908652848620018890558d8116808652601685528386208e875285528386208054938401815586528486209092018890558785526013845282852080546001600160a01b03191690921790915560149092529091208990557f000000000000000000000000ad3e1f40ffe9318cd7b83b42d01a8c72fcbb8ca71691506323b872dd90306138338888615c13565b6040518463ffffffff1660e01b815260040161385193929190615c87565b6020604051808303816000875af1158015613870573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138949190615c65565b5085876001600160a01b0316827f2f95efbf14694699c8a6ee93aea33c0b50ceb75a86d88934bb8772bb64f98a453389888a896040516138d8959493929190615f0e565b60405180910390a4506138ea60018055565b505050505050565b6138fa613b41565b6000818152601360209081526040808320546014909252909120546001600160a01b03909116908161393e5760405162461bcd60e51b815260040161081e90615e85565b6001600160a01b03808316600090815260116020908152604080832085845282528083208784529091529020805490911633146139b15760405162461bcd60e51b81526020600482015260116024820152702737ba1037b33332b91031b932b0ba37b960791b604482015260640161081e565b6000600582015460ff1660038111156139cc576139cc6155a2565b146139e95760405162461bcd60e51b815260040161081e90615ee0565b60058101805460ff1916600390811790915581015460028201546001600160a01b037f000000000000000000000000ad3e1f40ffe9318cd7b83b42d01a8c72fcbb8ca7169163a9059cbb913391613a3f91615c13565b6040518363ffffffff1660e01b8152600401613a5c929190615c4c565b6020604051808303816000875af1158015613a7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a9f9190615c65565b50604051339085907f1f51377b3e685a0e2419f9bb4ba7c07ec54936353ba3d0fb3c6538dab676622290600090a350505061115e60018055565b613ae1613b14565b6001600160a01b038116613b0b576000604051631e4fbdf760e01b815260040161081e919061585c565b61115e8161453e565b6000546001600160a01b0316331461241a573360405163118cdaa760e01b815260040161081e919061585c565b600260015403613b6457604051633ee5aeb560e01b815260040160405180910390fd5b6002600155565b60606000806040518060a001604052808b6001600160a01b031681526020018a8152602001896001600160a01b031681526020018660ff168152602001856001811115613bba57613bba6155a2565b905290506000613bcb898784614f73565b90506000613bd98284614ff4565b9050801580613be85750808910155b15613c085760408051600081526020810190915294509250613c1d915050565b613c1582848b8b85615056565b945094505050505b97509795505050505050565b6001600160a01b0387166000908152600c602052604090205460ff16613c615760405162461bcd60e51b815260040161081e90615cf6565b60008511613c815760405162461bcd60e51b815260040161081e90615d50565b60008411613cc75760405162461bcd60e51b8152602060048201526013602482015272496e76616c696420737461727420707269636560681b604482015260640161081e565b60008311613d135760405162461bcd60e51b8152602060048201526019602482015278125b9d985b1a59081b5a5b88189a59081a5b98dc995b595b9d603a1b604482015260640161081e565b6008548210158015613d2757506009548211155b613d665760405162461bcd60e51b815260206004820152601060248201526f24b73b30b634b210323ab930ba34b7b760811b604482015260640161081e565b6001816001811115613d7a57613d7a6155a2565b03613f3b5784600114613d9f5760405162461bcd60e51b815260040161081e90615d7a565b6040516331a9108f60e11b81526004810187905233906001600160a01b03891690636352211e90602401602060405180830381865afa158015613de6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e0a9190615b26565b6001600160a01b031614613e305760405162461bcd60e51b815260040161081e90615dad565b60405163020604bf60e21b81526004810187905230906001600160a01b0389169063081812fc90602401602060405180830381865afa158015613e77573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e9b9190615b26565b6001600160a01b03161480613f1a575060405163e985e9c560e01b81526001600160a01b0388169063e985e9c590613ed99033903090600401615dd6565b602060405180830381865afa158015613ef6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f1a9190615c65565b613f365760405162461bcd60e51b815260040161081e90615df0565b614053565b604051627eeac760e11b815285906001600160a01b0389169062fdd58e90613f699033908b90600401615c4c565b602060405180830381865afa158015613f86573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613faa9190615e16565b1015613fc85760405162461bcd60e51b815260040161081e90615e2f565b60405163e985e9c560e01b81526001600160a01b0388169063e985e9c590613ff69033903090600401615dd6565b602060405180830381865afa158015614013573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140379190615c65565b6140535760405162461bcd60e51b815260040161081e90615df0565b6001600160a01b0387166000908152600b6020908152604080832089845282528083203384529091529020600281015415806140e457506001600382015460ff1660018111156140a5576140a56155a2565b1480156140e45750600060048201546000908152600e6020526040902060080154600160a01b900460ff1660028111156140e1576140e16155a2565b14155b6141005760405162461bcd60e51b815260040161081e90615e5d565b5050505050505050565b6040805160c081018252338152602081018590529081018590526060810160018152602001838152602001826001811115614147576141476155a2565b90526001600160a01b038781166000908152600b602090815260408083208a84528252808320338452825291829020845181546001600160a01b031916941693909317835583015160018084019190915590830151600283015560608301516003830180549192909160ff19169083818111156141c6576141c66155a2565b02179055506080820151600482015560a082015160058201805460ff1916600183818111156141f7576141f76155a2565b021790555090505084866001600160a01b03167f24a1c41b19e085f48ac3aebb0b817e1076c3b1c5842d40a110da264537cbe800338688600188886040516142449695949392919061580f565b60405180910390a3505050505050565b4260006142618483615ce3565b9050604051806101600160405280336001600160a01b0316815260200187815260200187815260200186815260200183815260200182815260200189815260200188815260200160006001600160a01b03168152602001600060028111156142cb576142cb6155a2565b81526020018460018111156142e2576142e26155a2565b905260008b8152600e6020908152604091829020835181546001600160a01b03199081166001600160a01b0392831617835592850151600183015592840151600280830191909155606085015160038301556080850151600483015560a0850151600583015560c0850151600683015560e08501516007830155610100850151600883018054948516919095169081178555610120860151929492936001600160a81b0319161790600160a01b9084908111156143a1576143a16155a2565b021790555061014082015160088201805460ff60a81b1916600160a81b8360018111156143d0576143d06155a2565b0217905550505060008a815260106020526040902080546001600160a01b0319166001600160a01b038b161790556001836001811115614412576144126155a2565b0361447e57604051632142170760e11b81526001600160a01b038a16906342842e0e9061444790339030908d90600401615c87565b600060405180830381600087803b15801561446157600080fd5b505af1158015614475573d6000803e3d6000fd5b505050506144e3565b604051637921219560e11b81526001600160a01b038a169063f242432a906144b090339030908d908d90600401615cab565b600060405180830381600087803b1580156144ca57600080fd5b505af11580156144de573d6000803e3d6000fd5b505050505b87896001600160a01b03168b7f77445f9ade6cac698ef9dad2bdb9f4eb8cb6389e167068de61dc6bdd2458872b338a8a88888f8c60405161452a9796959493929190615f4d565b60405180910390a450505050505050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000818152601360205260408120546001600160a01b03169080826145c55760405162461bcd60e51b815260040161081e90615e85565b50506000828152601460209081526040808320546001600160a01b038516845260118352818420818552835281842086855290925282209091600582015460ff166003811115614617576146176155a2565b146146345760405162461bcd60e51b815260040161081e90615ee0565b60018101546001600160a01b03163314611ade5760405162461bcd60e51b8152602060048201526013602482015272139bdd081bd999995c881c9958da5c1a595b9d606a1b604482015260640161081e565b600060018260c0015160018111156146a0576146a06155a2565b0361473e576040516331a9108f60e11b81526004810184905233906001600160a01b03861690636352211e90602401602060405180830381865afa1580156146ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147109190615b26565b6001600160a01b0316146147365760405162461bcd60e51b815260040161081e90615dad565b506001611be4565b604051627eeac760e11b81526000906001600160a01b0386169062fdd58e9061476d9033908890600401615c4c565b602060405180830381865afa15801561478a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147ae9190615e16565b905082606001518110156147d45760405162461bcd60e51b815260040161081e90615e2f565b9050611be4565b6001600160a01b0384166000908152600b60209081526040808320868452825280832033845290915290206001600382015460ff166001811115614821576148216155a2565b0361489f57600060048201546000908152600e6020526040902060080154600160a01b900460ff16600281111561485a5761485a6155a2565b0361489f5760405162461bcd60e51b81526020600482015260156024820152744163746976652061756374696f6e2065786973747360581b604482015260640161081e565b600281015460006148b08285615b9a565b90506000858210156148c257816148c4565b855b905060006148d28288615b9a565b905080156149ee57838103614996576001600160a01b0389166000818152600b602090815260408083208c845282528083203380855290835281842080546001600160a01b0319168155600181018590556002810185905560038101805460ff19908116909155600482019590955560050180549094169093558051928352908201819052600d908201526c5a45524f5f5155414e5449545960981b6060820152899190600080516020615f8a8339815191529060800160405180910390a36149ee565b6149a08185615b9a565b6002860181905560405189916001600160a01b038c16917f36dba6da50cf7eb05d1a346c00f785d8a335ca42221245492e6e243624ce71fb916149e591339190615c4c565b60405180910390a35b505050505050505050565b60016005830154610100900460ff166001811115614a1957614a196155a2565b14614a925760405163e985e9c560e01b81526001600160a01b0385169063e985e9c590614a4c9033903090600401615dd6565b602060405180830381865afa158015614a69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614a8d9190615c65565b614b7c565b60405163020604bf60e21b81526004810184905230906001600160a01b0386169063081812fc90602401602060405180830381865afa158015614ad9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614afd9190615b26565b6001600160a01b03161480614b7c575060405163e985e9c560e01b81526001600160a01b0385169063e985e9c590614b3b9033903090600401615dd6565b602060405180830381865afa158015614b58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614b7c9190615c65565b614b985760405162461bcd60e51b815260040161081e90615df0565b604051636a4731c560e11b8152600481018490526000906001600160a01b0386169063d48e638a90602401602060405180830381865afa158015614be0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614c049190615b26565b600354909150336001600160a01b03831603614c1f57506002545b6000866001600160a01b03166359c8b7dd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614c5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614c839190615bef565b9050600085600301548660020154614c9b9190615c13565b905060006103e8614cac8584615c13565b614cb69190615c2a565b905060006103e8614ccb61ffff861685615c13565b614cd59190615c2a565b9050600081614ce48486615b9a565b614cee9190615b9a565b9050600160058a0154610100900460ff166001811115614d1057614d106155a2565b03614d7f578854604051632142170760e11b81526001600160a01b03808e16926342842e0e92614d4892339216908f90600401615c87565b600060405180830381600087803b158015614d6257600080fd5b505af1158015614d76573d6000803e3d6000fd5b50505050614dff565b8a6001600160a01b031663f242432a338b60000160009054906101000a90046001600160a01b03168d8d600301546040518563ffffffff1660e01b8152600401614dcc9493929190615cab565b600060405180830381600087803b158015614de657600080fd5b505af1158015614dfa573d6000803e3d6000fd5b505050505b60405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000ad3e1f40ffe9318cd7b83b42d01a8c72fcbb8ca7169063a9059cbb90614e4d9033908590600401615c4c565b6020604051808303816000875af1158015614e6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614e909190615c65565b508115614f2a5760405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000ad3e1f40ffe9318cd7b83b42d01a8c72fcbb8ca7169063a9059cbb90614ee5908a908690600401615c4c565b6020604051808303816000875af1158015614f04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614f289190615c65565b505b60058901805460ff19166001179055604051339089907fa7a40af5a1d0c10a3eb94af90cb008170915e8a71a6aaff052794cd762c72fc090600090a35050505050505050505050565b60008260ff16600003614fad575080516001600160a01b031660009081526016602090815260408083208285015184529091529020611be4565b8260ff16600103614fd657506001600160a01b0383166000908152601560205260409020611be4565b506001600160a01b0383166000908152601260205260409020611be4565b60008060005b845481101561504e5761502985828154811061501857615018615bad565b90600052602060002001548561516b565b1561503c578161503881615b59565b9250505b8061504681615b59565b915050614ffa565b509392505050565b60606000806150658685615b9a565b9050848111156150725750835b806001600160401b0381111561508a5761508a6152d4565b6040519080825280602002602001820160405280156150b3578160200160208202803683370190505b50925060008060005b8a54811080156150cb57508383105b1561515a5760008b82815481106150e4576150e4615bad565b906000526020600020015490506150fb818c61516b565b15615146578983101561511b578261511281615b59565b93505050615148565b80878561512781615b59565b96508151811061513957615139615bad565b6020026020010181815250505b505b8061515281615b59565b9150506150bc565b508593505050509550959350505050565b60008281526013602090815260408083205460148352818420546001600160a01b03909116808552601184528285208286528452828520878652909352908320606085015160ff1684036152075784516001600160a01b0384811691161480156151d85750846020015182145b80156151fd575060005b600582015460ff1660038111156151fb576151fb6155a2565b145b93505050506107ee565b846060015160ff1660010361523c57604085015160018201546001600160a01b0390811691161480156151fd575060006151e2565b604085015181546001600160a01b0390811691161480156151fd575060006151e2565b60006020828403121561527157600080fd5b81356001600160e01b031981168114611be457600080fd5b6001600160a01b038116811461115e57600080fd5b6000602082840312156152b057600080fd5b8135611be481615289565b6000602082840312156152cd57600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715615312576153126152d4565b604052919050565b600082601f83011261532b57600080fd5b81356001600160401b03811115615344576153446152d4565b615357601f8201601f19166020016152ea565b81815284602083860101111561536c57600080fd5b816020850160208301376000918101602001919091529392505050565b6000806000806080858703121561539f57600080fd5b84356153aa81615289565b935060208501356153ba81615289565b92506040850135915060608501356001600160401b038111156153dc57600080fd5b6153e88782880161531a565b91505092959194509250565b60008060006060848603121561540957600080fd5b833561541481615289565b95602085013595506040909401359392505050565b600081518084526020808501945080840160005b838110156154625781516001600160a01b03168752958201959082019060010161543d565b509495945050505050565b6040815260006154806040830185615429565b90508260208301529392505050565b604080825283519082018190526000906020906060840190828701845b828110156154c8578151845292840192908401906001016154ac565b50505092019290925292915050565b600080604083850312156154ea57600080fd5b8235915060208301356154fc81615289565b809150509250929050565b6000806040838503121561551a57600080fd5b50508035926020909101359150565b602081526000611be46020830184615429565b80356002811061554b57600080fd5b919050565b600080600080600060a0868803121561556857600080fd5b853561557381615289565b94506020860135935060408601359250606086013591506155966080870161553c565b90509295509295909350565b634e487b7160e01b600052602160045260246000fd5b600481106155c8576155c86155a2565b9052565b6002811061115e5761115e6155a2565b60006101208201905060018060a01b0380861683528460208401528084511660408401528060208501511660608401525060408301516080830152606083015160a0830152608083015160c083015260a083015161563d60e08401826155b8565b5060c083015161564c816155cc565b8061010084015250949350505050565b60008060006060848603121561567157600080fd5b833561567c81615289565b925060208401359150604084013561569381615289565b809150509250925092565b81516001600160a01b031681526020808301519082015260408083015190820152606082015160c08201906156d2816155cc565b60608301526080838101519083015260a08301516156ef816155cc565b8060a08401525092915050565b600080600080600080600060e0888a03121561571757600080fd5b873561572281615289565b96506020880135955060408801359450606088013593506080880135925060a0880135915061575360c0890161553c565b905092959891949750929550565b6001600160a01b038c81168252602082018c9052604082018b9052606082018a90526080820189905260a0820188905260c0820187905260e0820186905284166101008201526101608101600384106157bc576157bc6155a2565b836101208301526157cc836155cc565b826101408301529c9b505050505050505050505050565b600080604083850312156157f657600080fd5b823561580181615289565b946020939093013593505050565b6001600160a01b0387168152602081018690526040810185905260c08101615836856155cc565b84606083015283608083015261584b836155cc565b8260a0830152979650505050505050565b6001600160a01b0391909116815260200190565b600080600080600060a0868803121561588857600080fd5b853561589381615289565b94506020860135935060408601356158aa81615289565b9250606086013591506155966080870161553c565b600082601f8301126158d057600080fd5b813560206001600160401b038211156158eb576158eb6152d4565b8160051b6158fa8282016152ea565b928352848101820192828101908785111561591457600080fd5b83870192505b84831015611d8b5782358252918301919083019061591a565b600080600080600060a0868803121561594b57600080fd5b853561595681615289565b9450602086013561596681615289565b935060408601356001600160401b038082111561598257600080fd5b61598e89838a016158bf565b945060608801359150808211156159a457600080fd5b6159b089838a016158bf565b935060808801359150808211156159c657600080fd5b506159d38882890161531a565b9150509295509295909350565b6001600160a01b0388811682528716602082015260408101869052606081018590526080810184905260e08101615a1a60a08301856155b8565b615a23836155cc565b8260c083015298975050505050505050565b60008060008060008060c08789031215615a4e57600080fd5b8635615a5981615289565b9550602087013594506040870135615a7081615289565b93506060870135925060808701359150615a8c60a0880161553c565b90509295509295509295565b600080600080600060a08688031215615ab057600080fd5b8535615abb81615289565b94506020860135615acb81615289565b9350604086013592506060860135915060808601356001600160401b03811115615af457600080fd5b6159d38882890161531a565b6020808252600c908201526b08ccaca40e8dede40d0d2ced60a31b604082015260600190565b600060208284031215615b3857600080fd5b8151611be481615289565b634e487b7160e01b600052601160045260246000fd5b600060018201615b6b57615b6b615b43565b5060010190565b6020808252600e908201526d125b9d985b1a59081bd9999cd95d60921b604082015260600190565b818103818111156107ee576107ee615b43565b634e487b7160e01b600052603260045260246000fd5b60208082526012908201527141756374696f6e206e6f742061637469766560701b604082015260600190565b600060208284031215615c0157600080fd5b815161ffff81168114611be457600080fd5b80820281158282048414176107ee576107ee615b43565b600082615c4757634e487b7160e01b600052601260045260246000fd5b500490565b6001600160a01b03929092168252602082015260400190565b600060208284031215615c7757600080fd5b81518015158114611be457600080fd5b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b0394851681529290931660208301526040820152606081019190915260a06080820181905260009082015260c00190565b808201808211156107ee576107ee615b43565b60208082526019908201527810dbdb1b1958dd1a5bdb881b9bdd081c9959da5cdd195c9959603a1b604082015260600190565b6020808252600d908201526c496e76616c696420707269636560981b604082015260600190565b60208082526010908201526f496e76616c6964207175616e7469747960801b604082015260600190565b602080825260199082015278455243373231207175616e74697479206d757374206265203160381b604082015260600190565b6020808252600f908201526e2737ba103a37b5b2b71037bbb732b960891b604082015260600190565b6001600160a01b0392831681529116602082015260400190565b6020808252600c908201526b139bdd08185c1c1c9bdd995960a21b604082015260600190565b600060208284031215615e2857600080fd5b5051919050565b602080825260149082015273496e73756666696369656e742062616c616e636560601b604082015260600190565b6020808252600e908201526d105b1c9958591e481b1a5cdd195960921b604082015260600190565b60208082526014908201527313d999995c88191bd95cc81b9bdd08195e1a5cdd60621b604082015260600190565b602080825260139082015272109a591cc8185b1c9958591e481c1b1858d959606a1b604082015260600190565b602080825260149082015273496e76616c6964206f666665722073746174757360601b604082015260600190565b6001600160a01b03868116825285166020820152604081018490526060810183905260a08101615f3d836155cc565b8260808301529695505050505050565b6001600160a01b03881681526020810187905260408101869052606081018590526080810184905260a0810183905260e08101615a23836155cc56fe17d654f862f895d7741bf4e3234b08875e872e59e08d21c44d35187a60cfa2a2a2646970667358221220bc71d3d5b240b8e004a458e89c2348308d515d9a328fc4ba05dbc8418026ebc264736f6c63430008140033