Transactions
Token Transfers
Tokens
Internal Transactions
Coin Balance History
Logs
Code
Read Contract
Write Contract
- Contract name:
- NFTMarket
- Optimization enabled
- true
- Compiler version
- v0.8.10+commit.fc410830
- Optimization runs
- 200
- EVM Version
- default
- Verified at
- 2022-02-15T20:51:34.512526Z
Constructor Arguments
0000000000000000000000008073ff672d69f6a2060d0042b0adec608c1cbfe800000000000000000000000059c6b627b9f35663b2258eb1ac6da499cf3e4c47000000000000000000000000109a473d0465dd638aa2ad2f9104205f3598e342
Arg [0] (address) : 0x8073ff672d69f6a2060d0042b0adec608c1cbfe8
Arg [1] (address) : 0x59c6b627b9f35663b2258eb1ac6da499cf3e4c47
Arg [2] (address) : 0x109a473d0465dd638aa2ad2f9104205f3598e342
Contract source code
// File: @openzeppelin/contracts/utils/introspection/IERC165.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
// File: @openzeppelin/contracts/token/ERC721/IERC721.sol
pragma solidity ^0.8.0;
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be 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: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
*
* 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 Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool _approved) external;
/**
* @dev Returns 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);
/**
* @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;
}
// File: @openzeppelin/contracts/token/ERC721/IERC721Receiver.sol
pragma solidity ^0.8.0;
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 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 `IERC721.onERC721Received.selector`.
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
// File: @openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol
pragma solidity ^0.8.0;
/**
* @title ERC-721 Non-Fungible Token Standard, optional metadata extension
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/
interface IERC721Metadata is IERC721 {
/**
* @dev Returns the token collection name.
*/
function name() external view returns (string memory);
/**
* @dev Returns the token collection symbol.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
*/
function tokenURI(uint256 tokenId) external view returns (string memory);
}
// File: @openzeppelin/contracts/utils/Address.sol
pragma solidity ^0.8.0;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize, which returns 0 for contracts in
// construction, since the code is only stored at the end of the
// constructor execution.
uint256 size;
assembly {
size := extcodesize(account)
}
return size > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
// File: @openzeppelin/contracts/utils/Context.sol
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
// File: @openzeppelin/contracts/utils/Strings.sol
pragma solidity ^0.8.0;
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
// Inspired by OraclizeAPI's implementation - MIT licence
// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _HEX_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
}
// File: @openzeppelin/contracts/utils/introspection/ERC165.sol
pragma solidity ^0.8.0;
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
// File: @openzeppelin/contracts/token/ERC721/ERC721.sol
pragma solidity ^0.8.0;
/**
* @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
* the Metadata extension, but not including the Enumerable extension, which is available separately as
* {ERC721Enumerable}.
*/
contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
using Address for address;
using Strings for uint256;
// Token name
string private _name;
// Token symbol
string private _symbol;
// Mapping from token ID to owner address
mapping(uint256 => address) private _owners;
// Mapping owner address to token count
mapping(address => uint256) private _balances;
// Mapping from token ID to approved address
mapping(uint256 => address) private _tokenApprovals;
// Mapping from owner to operator approvals
mapping(address => mapping(address => bool)) private _operatorApprovals;
/**
* @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return
interfaceId == type(IERC721).interfaceId ||
interfaceId == type(IERC721Metadata).interfaceId ||
super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC721-balanceOf}.
*/
function balanceOf(address owner) public view virtual override returns (uint256) {
require(owner != address(0), "ERC721: balance query for the zero address");
return _balances[owner];
}
/**
* @dev See {IERC721-ownerOf}.
*/
function ownerOf(uint256 tokenId) public view virtual override returns (address) {
address owner = _owners[tokenId];
require(owner != address(0), "ERC721: owner query for nonexistent token");
return owner;
}
/**
* @dev See {IERC721Metadata-name}.
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @dev See {IERC721Metadata-symbol}.
*/
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
/**
* @dev See {IERC721Metadata-tokenURI}.
*/
function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
string memory baseURI = _baseURI();
return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
}
/**
* @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
* token will be the concatenation of the `baseURI` and the `tokenId`. Empty
* by default, can be overriden in child contracts.
*/
function _baseURI() internal view virtual returns (string memory) {
return "";
}
/**
* @dev See {IERC721-approve}.
*/
function approve(address to, uint256 tokenId) public virtual override {
address owner = ERC721.ownerOf(tokenId);
require(to != owner, "ERC721: approval to current owner");
require(
_msgSender() == owner || isApprovedForAll(owner, _msgSender()),
"ERC721: approve caller is not owner nor approved for all"
);
_approve(to, tokenId);
}
/**
* @dev See {IERC721-getApproved}.
*/
function getApproved(uint256 tokenId) public view virtual override returns (address) {
require(_exists(tokenId), "ERC721: approved query for nonexistent token");
return _tokenApprovals[tokenId];
}
/**
* @dev See {IERC721-setApprovalForAll}.
*/
function setApprovalForAll(address operator, bool approved) public virtual override {
require(operator != _msgSender(), "ERC721: approve to caller");
_operatorApprovals[_msgSender()][operator] = approved;
emit ApprovalForAll(_msgSender(), operator, approved);
}
/**
* @dev See {IERC721-isApprovedForAll}.
*/
function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
return _operatorApprovals[owner][operator];
}
/**
* @dev See {IERC721-transferFrom}.
*/
function transferFrom(
address from,
address to,
uint256 tokenId
) public virtual override {
//solhint-disable-next-line max-line-length
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
_transfer(from, to, tokenId);
}
/**
* @dev See {IERC721-safeTransferFrom}.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) public virtual override {
safeTransferFrom(from, to, tokenId, "");
}
/**
* @dev See {IERC721-safeTransferFrom}.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes memory _data
) public virtual override {
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
_safeTransfer(from, to, tokenId, _data);
}
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* `_data` is additional data, it has no specified format and it is sent in call to `to`.
*
* This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
* implement alternative mechanisms to perform token transfer, such as signature-based.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function _safeTransfer(
address from,
address to,
uint256 tokenId,
bytes memory _data
) internal virtual {
_transfer(from, to, tokenId);
require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
}
/**
* @dev Returns whether `tokenId` exists.
*
* Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
*
* Tokens start existing when they are minted (`_mint`),
* and stop existing when they are burned (`_burn`).
*/
function _exists(uint256 tokenId) internal view virtual returns (bool) {
return _owners[tokenId] != address(0);
}
/**
* @dev Returns whether `spender` is allowed to manage `tokenId`.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
require(_exists(tokenId), "ERC721: operator query for nonexistent token");
address owner = ERC721.ownerOf(tokenId);
return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
}
/**
* @dev Safely mints `tokenId` and transfers it to `to`.
*
* Requirements:
*
* - `tokenId` must not exist.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function _safeMint(address to, uint256 tokenId) internal virtual {
_safeMint(to, tokenId, "");
}
/**
* @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
* forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
*/
function _safeMint(
address to,
uint256 tokenId,
bytes memory _data
) internal virtual {
_mint(to, tokenId);
require(
_checkOnERC721Received(address(0), to, tokenId, _data),
"ERC721: transfer to non ERC721Receiver implementer"
);
}
/**
* @dev Mints `tokenId` and transfers it to `to`.
*
* WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
*
* Requirements:
*
* - `tokenId` must not exist.
* - `to` cannot be the zero address.
*
* Emits a {Transfer} event.
*/
function _mint(address to, uint256 tokenId) internal virtual {
require(to != address(0), "ERC721: mint to the zero address");
require(!_exists(tokenId), "ERC721: token already minted");
_beforeTokenTransfer(address(0), to, tokenId);
_balances[to] += 1;
_owners[tokenId] = to;
emit Transfer(address(0), to, tokenId);
}
/**
* @dev Destroys `tokenId`.
* The approval is cleared when the token is burned.
*
* Requirements:
*
* - `tokenId` must exist.
*
* Emits a {Transfer} event.
*/
function _burn(uint256 tokenId) internal virtual {
address owner = ERC721.ownerOf(tokenId);
_beforeTokenTransfer(owner, address(0), tokenId);
// Clear approvals
_approve(address(0), tokenId);
_balances[owner] -= 1;
delete _owners[tokenId];
emit Transfer(owner, address(0), tokenId);
}
/**
* @dev Transfers `tokenId` from `from` to `to`.
* As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
*
* Emits a {Transfer} event.
*/
function _transfer(
address from,
address to,
uint256 tokenId
) internal virtual {
require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own");
require(to != address(0), "ERC721: transfer to the zero address");
_beforeTokenTransfer(from, to, tokenId);
// Clear approvals from the previous owner
_approve(address(0), tokenId);
_balances[from] -= 1;
_balances[to] += 1;
_owners[tokenId] = to;
emit Transfer(from, to, tokenId);
}
/**
* @dev Approve `to` to operate on `tokenId`
*
* Emits a {Approval} event.
*/
function _approve(address to, uint256 tokenId) internal virtual {
_tokenApprovals[tokenId] = to;
emit Approval(ERC721.ownerOf(tokenId), to, tokenId);
}
/**
* @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
* The call is not executed if the target address is not a contract.
*
* @param from address representing the previous owner of the given token ID
* @param to target address that will receive the tokens
* @param tokenId uint256 ID of the token to be transferred
* @param _data bytes optional data to send along with the call
* @return bool whether the call correctly returned the expected magic value
*/
function _checkOnERC721Received(
address from,
address to,
uint256 tokenId,
bytes memory _data
) private returns (bool) {
if (to.isContract()) {
try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) {
return retval == IERC721Receiver.onERC721Received.selector;
} catch (bytes memory reason) {
if (reason.length == 0) {
revert("ERC721: transfer to non ERC721Receiver implementer");
} else {
assembly {
revert(add(32, reason), mload(reason))
}
}
}
} else {
return true;
}
}
/**
* @dev Hook that is called before any token transfer. This includes minting
* and burning.
*
* Calling conditions:
*
* - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be
* transferred to `to`.
* - When `from` is zero, `tokenId` will be minted for `to`.
* - When `to` is zero, ``from``'s `tokenId` will be burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(
address from,
address to,
uint256 tokenId
) internal virtual {}
}
// File: @openzeppelin/contracts/token/ERC1155/IERC1155.sol
pragma solidity ^0.8.0;
/**
* @dev Required interface of an ERC1155 compliant contract, as defined in the
* https://eips.ethereum.org/EIPS/eip-1155[EIP].
*
* _Available since v3.1._
*/
interface IERC1155 is IERC165 {
/**
* @dev Emitted when `value` tokens of token 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 amount of tokens of token type `id` owned by `account`.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
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 caller.
*/
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 `amount` tokens of token type `id` from `from` to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - If the caller is not `from`, it must be have been approved to spend ``from``'s tokens via {setApprovalForAll}.
* - `from` must have a balance of tokens of type `id` of at least `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 amount,
bytes calldata data
) external;
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `ids` and `amounts` 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 amounts,
bytes calldata data
) external;
}
// File: @openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol
pragma solidity ^0.8.0;
/**
* @dev _Available since v3.1._
*/
interface IERC1155Receiver is IERC165 {
/**
@dev Handles the receipt of a single ERC1155 token type. This function is
called at the end of a `safeTransferFrom` after the balance has been updated.
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 ERC1155 token types. This function
is called at the end of a `safeBatchTransferFrom` after the balances have
been updated. To accept the transfer(s), this must return
`bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
(i.e. 0xbc197c81, or its own function selector).
@param operator The address which initiated the batch transfer (i.e. msg.sender)
@param from The address which previously owned the token
@param ids An array containing ids of each token being transferred (order and length must match values array)
@param values An array containing amounts of each token being transferred (order and length must match ids array)
@param data Additional data with no specified format
@return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
*/
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external returns (bytes4);
}
// File: @openzeppelin/contracts/token/ERC1155/utils/ERC1155Receiver.sol
pragma solidity ^0.8.0;
/**
* @dev _Available since v3.1._
*/
abstract contract ERC1155Receiver 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);
}
}
// File: @openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol
pragma solidity ^0.8.0;
/**
* @dev _Available since v3.1._
*/
contract ERC1155Holder is ERC1155Receiver {
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/utils/ERC721Holder.sol
pragma solidity ^0.8.0;
/**
* @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}.
*/
contract ERC721Holder is IERC721Receiver {
/**
* @dev See {IERC721Receiver-onERC721Received}.
*
* Always returns `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(
address,
address,
uint256,
bytes memory
) public virtual override returns (bytes4) {
return this.onERC721Received.selector;
}
}
// File: @openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol
pragma solidity ^0.8.0;
/**
* @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/
interface IERC721Enumerable is IERC721 {
/**
* @dev Returns the total amount of tokens stored by the contract.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns a token ID owned by `owner` at a given `index` of its token list.
* Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
*/
function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId);
/**
* @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
* Use along with {totalSupply} to enumerate all tokens.
*/
function tokenByIndex(uint256 index) external view returns (uint256);
}
// File: @openzeppelin/contracts/security/ReentrancyGuard.sol
pragma solidity ^0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and make it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
// On the first call to nonReentrant, _notEntered will be true
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
_;
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
}
// File: @openzeppelin/contracts/access/Ownable.sol
pragma solidity ^0.8.0;
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_setOwner(_msgSender());
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_setOwner(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_setOwner(newOwner);
}
function _setOwner(address newOwner) private {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
// File: contracts/interfaces/IMarketPlaceFeeContract.sol
pragma solidity 0.8.10;
interface IMarketPlaceFeeContract {
/**
* @notice Collects and pays marketplace fees for a transaction
* @param _user Address of the user performing the transaction
* @param _totalPrice Total transaction value
* @return transaction value left after fee deduction
*/
function _collectMarketFee(address _user, uint256 _totalPrice)
external
returns (uint256);
/**
* @notice Returns the market fees for a user
* @param _user Address of the user performing the transaction
* @return Fee percentage
*/
function _getMarketFee(address _user) external view returns (uint256);
}
// File: contracts/interfaces/IOwnableNFT.sol
pragma solidity 0.8.10;
interface IOwnableNFT {
/**
* @notice Returns the owner of an NFT Collection
* @return address of the owner
*/
function owner() external view returns (address);
}
// File: @openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol
pragma solidity ^0.8.0;
/**
* @dev This implements an optional extension of {ERC721} defined in the EIP that adds
* enumerability of all the token ids in the contract as well as all token ids owned by each
* account.
*/
abstract contract ERC721Enumerable is ERC721, IERC721Enumerable {
// Mapping from owner to list of owned token IDs
mapping(address => mapping(uint256 => uint256)) private _ownedTokens;
// Mapping from token ID to index of the owner tokens list
mapping(uint256 => uint256) private _ownedTokensIndex;
// Array with all token ids, used for enumeration
uint256[] private _allTokens;
// Mapping from token id to position in the allTokens array
mapping(uint256 => uint256) private _allTokensIndex;
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721) returns (bool) {
return interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
*/
function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) {
require(index < ERC721.balanceOf(owner), "ERC721Enumerable: owner index out of bounds");
return _ownedTokens[owner][index];
}
/**
* @dev See {IERC721Enumerable-totalSupply}.
*/
function totalSupply() public view virtual override returns (uint256) {
return _allTokens.length;
}
/**
* @dev See {IERC721Enumerable-tokenByIndex}.
*/
function tokenByIndex(uint256 index) public view virtual override returns (uint256) {
require(index < ERC721Enumerable.totalSupply(), "ERC721Enumerable: global index out of bounds");
return _allTokens[index];
}
/**
* @dev Hook that is called before any token transfer. This includes minting
* and burning.
*
* Calling conditions:
*
* - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be
* transferred to `to`.
* - When `from` is zero, `tokenId` will be minted for `to`.
* - When `to` is zero, ``from``'s `tokenId` will be burned.
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(
address from,
address to,
uint256 tokenId
) internal virtual override {
super._beforeTokenTransfer(from, to, tokenId);
if (from == address(0)) {
_addTokenToAllTokensEnumeration(tokenId);
} else if (from != to) {
_removeTokenFromOwnerEnumeration(from, tokenId);
}
if (to == address(0)) {
_removeTokenFromAllTokensEnumeration(tokenId);
} else if (to != from) {
_addTokenToOwnerEnumeration(to, tokenId);
}
}
/**
* @dev Private function to add a token to this extension's ownership-tracking data structures.
* @param to address representing the new owner of the given token ID
* @param tokenId uint256 ID of the token to be added to the tokens list of the given address
*/
function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
uint256 length = ERC721.balanceOf(to);
_ownedTokens[to][length] = tokenId;
_ownedTokensIndex[tokenId] = length;
}
/**
* @dev Private function to add a token to this extension's token tracking data structures.
* @param tokenId uint256 ID of the token to be added to the tokens list
*/
function _addTokenToAllTokensEnumeration(uint256 tokenId) private {
_allTokensIndex[tokenId] = _allTokens.length;
_allTokens.push(tokenId);
}
/**
* @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that
* while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for
* gas optimizations e.g. when performing a transfer operation (avoiding double writes).
* This has O(1) time complexity, but alters the order of the _ownedTokens array.
* @param from address representing the previous owner of the given token ID
* @param tokenId uint256 ID of the token to be removed from the tokens list of the given address
*/
function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private {
// To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and
// then delete the last slot (swap and pop).
uint256 lastTokenIndex = ERC721.balanceOf(from) - 1;
uint256 tokenIndex = _ownedTokensIndex[tokenId];
// When the token to delete is the last token, the swap operation is unnecessary
if (tokenIndex != lastTokenIndex) {
uint256 lastTokenId = _ownedTokens[from][lastTokenIndex];
_ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
_ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
}
// This also deletes the contents at the last position of the array
delete _ownedTokensIndex[tokenId];
delete _ownedTokens[from][lastTokenIndex];
}
/**
* @dev Private function to remove a token from this extension's token tracking data structures.
* This has O(1) time complexity, but alters the order of the _allTokens array.
* @param tokenId uint256 ID of the token to be removed from the tokens list
*/
function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
// To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and
// then delete the last slot (swap and pop).
uint256 lastTokenIndex = _allTokens.length - 1;
uint256 tokenIndex = _allTokensIndex[tokenId];
// When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so
// rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding
// an 'if' statement (like in _removeTokenFromOwnerEnumeration)
uint256 lastTokenId = _allTokens[lastTokenIndex];
_allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
_allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
// This also deletes the contents at the last position of the array
delete _allTokensIndex[tokenId];
_allTokens.pop();
}
}
// File: contracts/libraries/CustomOwnable.sol
pragma solidity ^0.8.0;
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract CustomOwnable is Context {
address private _owner;
event OwnershipTransferred(
address indexed previousOwner,
address indexed newOwner
);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor(address owner_) {
_owner = owner_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_setOwner(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(
newOwner != address(0),
"Ownable: new owner is the zero address"
);
_setOwner(newOwner);
}
function _setOwner(address newOwner) private {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
// File: contracts/NFT.sol
pragma solidity 0.8.10;
contract NFT is ERC721Enumerable, CustomOwnable {
using Strings for uint256;
bool public publicMinting;
string public baseExtension = ".json";
uint256 public cost = 0 ether;
uint256 public maxSupply;
uint256 public maxMintAmount;
uint256 public timeDeployed;
uint256 public allowMintingAfter = 0;
bool public isPaused = false;
bool public isRevealed = true;
uint256 public maxMintsPerAccount;
mapping(uint256 => string) public tokenURIs;
event PublicMintingEnabled(
uint256 _revealTime,
uint256 _maxSupply,
uint256 _maxMintAmount,
uint256 _cost,
uint256 _maxMintsPerAccount
);
event Withdrawal(address payee, uint256 amount);
/**
* @notice Initiates an NFT collection
* @param _name Name of the collection
* @param _symbol Symbol of the collection
* @param _owner Address of the contract owner
*/
constructor(
string memory _name,
string memory _symbol,
address _owner
) ERC721(_name, _symbol) CustomOwnable(_owner) {
timeDeployed = block.timestamp;
}
/**
* @notice Enables Public minting with time and max mint conditions
* @param _revealTime Time at which the URI for tokens are available to view
* @param _revealed True if the URI is revealed and False if not
* @param _maxSupply Maximum supply that can be minted
* @param _maxMintAmount Maximum mints per account per mint
* @param _cost Cost of minting a token
* @param _maxMintsPerAccount Maximum number of mints per account
*/
function enablePublicMinting(
uint256 _revealTime,
bool _revealed,
uint256 _maxSupply,
uint256 _maxMintAmount,
uint256 _cost,
uint256 _maxMintsPerAccount
) public onlyOwner {
publicMinting = true;
if (_revealTime > block.timestamp) {
allowMintingAfter = _revealTime - block.timestamp;
}
maxSupply = _maxSupply;
maxMintAmount = _maxMintAmount;
cost = _cost;
isRevealed = _revealed;
maxMintsPerAccount = _maxMintsPerAccount;
emit PublicMintingEnabled(
_revealTime,
_maxSupply,
_maxMintAmount,
_cost,
_maxMintsPerAccount
);
}
/**
* @notice Mints a new token for the msg.sender
* @param uri Metadata URI of the new token
* @param _owner Address the token should be minted to
* @return total supply of the tokens
*/
function createToken(string memory uri, address _owner)
public
onlyOwner
returns (uint256)
{
uint256 supply = totalSupply();
_safeMint(_owner, supply + 1);
tokenURIs[supply + 1] = uri;
return totalSupply();
}
/**
* @notice Mints multiple new tokens for the msg.sender
* @param uris Metadata URIs of the new token
* @param _mintAmount Number of tokens to be minted
*/
function batchCreateTokens(uint256 _mintAmount, string[] memory uris)
public
onlyOwner
{
uint256 supply = totalSupply();
require(!isPaused, "CONTRACT_PAUSED");
require(_mintAmount > 0, "INVALID_MINT_AMOUNT");
require(supply + _mintAmount <= maxSupply, "EXCEEDS_MAX_SUPPLY");
require(_mintAmount == uris.length, "URI_COUNT_MISMATCH");
for (uint256 i = 1; i <= _mintAmount; i++) {
_safeMint(msg.sender, supply + i);
tokenURIs[supply + i] = uris[i];
}
}
// PUBLIC FUNCTIONS
/**
* @notice Mints a new token for the msg.sender
* @param _mintAmount Number of tokens to be minted
* @param uris Metadata URIs of the new token
*/
function mint(uint256 _mintAmount, string[] memory uris) public payable {
require(publicMinting, "PUBLIC_MINTING_NOT_ENABLED");
require(
block.timestamp >= timeDeployed + allowMintingAfter,
"MINTING_NOT_ALLOWED_YET"
);
require(
balanceOf(msg.sender) < maxMintsPerAccount,
"MAX_MINTS_PER_ACCOUNT_EXCEEDED"
);
uint256 supply = totalSupply();
require(!isPaused, "CONTRACT_PAUSED");
require(
_mintAmount > 0 && _mintAmount <= maxMintAmount,
"INVALID_MINT_AMOUNT"
);
require(supply + _mintAmount <= maxSupply, "EXCEEDS_MAX_SUPPLY");
require(_mintAmount == uris.length, "URI_COUNT_MISMATCH");
if (msg.sender != owner()) {
require(
msg.value >= cost * _mintAmount,
"MSG_VALUE_LESS_THEN_COST"
);
}
for (uint256 i = 1; i <= _mintAmount; i++) {
_safeMint(msg.sender, supply + i);
tokenURIs[supply + i] = uris[i];
}
}
/**
* @notice Returns the token ids held by a user
* @param _owner Wallet to be tested for
* @return token Ids held by the user
*/
function walletOfOwner(address _owner)
public
view
returns (uint256[] memory)
{
uint256 ownerTokenCount = balanceOf(_owner);
uint256[] memory tokenIds = new uint256[](ownerTokenCount);
for (uint256 i; i < ownerTokenCount; i++) {
tokenIds[i] = tokenOfOwnerByIndex(_owner, i);
}
return tokenIds;
}
/**
* @notice Returns the token URI of a token
* @param tokenId Token ID for which URI is to be revealed
* @return tokenId - URI of the token
*/
function tokenURI(uint256 tokenId)
public
view
virtual
override
returns (string memory)
{
require(_exists(tokenId), "URI_QUERY_FOR_NON_EXISTENT_TOKEN");
return tokenURIs[tokenId];
}
/**
* @notice Revelas the number of seconds until public minting goes live
* @return Number of seconds until public minting starts
*/
function getSecondsUntilMinting() public view returns (uint256) {
if (block.timestamp < timeDeployed + allowMintingAfter) {
return (timeDeployed + allowMintingAfter) - block.timestamp;
} else {
return 0;
}
}
// ONLY OWNER FUNCTIONS
/**
* @notice Sets reveal status for the collection
* @param _state New state of reveal
*/
function setIsRevealed(bool _state) public onlyOwner {
isRevealed = _state;
}
/**
* @notice Sets cost of minting new token
* @param _newCost New cost of minting
*/
function setCost(uint256 _newCost) public onlyOwner {
cost = _newCost;
}
/**
* @notice Sets maximum mint amount
* @param _newmaxMintAmount New maximum mint amount
*/
function setmaxMintAmount(uint256 _newmaxMintAmount) public onlyOwner {
maxMintAmount = _newmaxMintAmount;
}
/**
* @notice Sets the paused status of the collection
* @param _state New paused state of the collection
*/
function setIsPaused(bool _state) public onlyOwner {
isPaused = _state;
}
/**
* @notice enables admin withdrawal of funds from the protocol
*/
function withdraw() public payable onlyOwner {
uint256 balance = address(this).balance;
payable(msg.sender).transfer(balance);
require(address(this).balance == 0, "TRANSFER_FAILED");
emit Withdrawal(msg.sender, balance);
}
}
// File: @openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol
pragma solidity ^0.8.0;
/**
* @dev Interface of the optional ERC1155MetadataExtension interface, as defined
* in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].
*
* _Available since v3.1._
*/
interface IERC1155MetadataURI is IERC1155 {
/**
* @dev Returns the URI for token type `id`.
*
* If the `\{id\}` substring is present in the URI, it must be replaced by
* clients with the actual token type ID.
*/
function uri(uint256 id) external view returns (string memory);
}
// File: @openzeppelin/contracts/token/ERC1155/ERC1155.sol
pragma solidity ^0.8.0;
/**
* @dev Implementation of the basic standard multi-token.
* See https://eips.ethereum.org/EIPS/eip-1155
* Originally based on code by Enjin: https://github.com/enjin/erc-1155
*
* _Available since v3.1._
*/
contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {
using Address for address;
// Mapping from token ID to account balances
mapping(uint256 => mapping(address => uint256)) private _balances;
// Mapping from account to operator approvals
mapping(address => mapping(address => bool)) private _operatorApprovals;
// Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json
string private _uri;
/**
* @dev See {_setURI}.
*/
constructor(string memory uri_) {
_setURI(uri_);
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return
interfaceId == type(IERC1155).interfaceId ||
interfaceId == type(IERC1155MetadataURI).interfaceId ||
super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC1155MetadataURI-uri}.
*
* This implementation returns the same URI for *all* token types. It relies
* on the token type ID substitution mechanism
* https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
*
* Clients calling this function must replace the `\{id\}` substring with the
* actual token type ID.
*/
function uri(uint256) public view virtual override returns (string memory) {
return _uri;
}
/**
* @dev See {IERC1155-balanceOf}.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {
require(account != address(0), "ERC1155: balance query for the zero address");
return _balances[id][account];
}
/**
* @dev See {IERC1155-balanceOfBatch}.
*
* Requirements:
*
* - `accounts` and `ids` must have the same length.
*/
function balanceOfBatch(address[] memory accounts, uint256[] memory ids)
public
view
virtual
override
returns (uint256[] memory)
{
require(accounts.length == ids.length, "ERC1155: accounts and ids length mismatch");
uint256[] memory batchBalances = new uint256[](accounts.length);
for (uint256 i = 0; i < accounts.length; ++i) {
batchBalances[i] = balanceOf(accounts[i], ids[i]);
}
return batchBalances;
}
/**
* @dev See {IERC1155-setApprovalForAll}.
*/
function setApprovalForAll(address operator, bool approved) public virtual override {
require(_msgSender() != operator, "ERC1155: setting approval status for self");
_operatorApprovals[_msgSender()][operator] = approved;
emit ApprovalForAll(_msgSender(), operator, approved);
}
/**
* @dev See {IERC1155-isApprovedForAll}.
*/
function isApprovedForAll(address account, address operator) public view virtual override returns (bool) {
return _operatorApprovals[account][operator];
}
/**
* @dev See {IERC1155-safeTransferFrom}.
*/
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) public virtual override {
require(
from == _msgSender() || isApprovedForAll(from, _msgSender()),
"ERC1155: caller is not owner nor approved"
);
_safeTransferFrom(from, to, id, amount, data);
}
/**
* @dev See {IERC1155-safeBatchTransferFrom}.
*/
function safeBatchTransferFrom(
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) public virtual override {
require(
from == _msgSender() || isApprovedForAll(from, _msgSender()),
"ERC1155: transfer caller is not owner nor approved"
);
_safeBatchTransferFrom(from, to, ids, amounts, data);
}
/**
* @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `from` must have a balance of tokens of type `id` of at least `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 amount,
bytes memory data
) internal virtual {
require(to != address(0), "ERC1155: transfer to the zero address");
address operator = _msgSender();
_beforeTokenTransfer(operator, from, to, _asSingletonArray(id), _asSingletonArray(amount), data);
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");
unchecked {
_balances[id][from] = fromBalance - amount;
}
_balances[id][to] += amount;
emit TransferSingle(operator, from, to, id, amount);
_doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);
}
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - 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[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
require(to != address(0), "ERC1155: transfer to the zero address");
address operator = _msgSender();
_beforeTokenTransfer(operator, from, to, ids, amounts, data);
for (uint256 i = 0; i < ids.length; ++i) {
uint256 id = ids[i];
uint256 amount = amounts[i];
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");
unchecked {
_balances[id][from] = fromBalance - amount;
}
_balances[id][to] += amount;
}
emit TransferBatch(operator, from, to, ids, amounts);
_doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);
}
/**
* @dev Sets a new URI for all token types, by relying on the token type ID
* substitution mechanism
* https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
*
* By this mechanism, any occurrence of the `\{id\}` substring in either the
* URI or any of the amounts in the JSON file at said URI will be replaced by
* clients with the token type ID.
*
* For example, the `https://token-cdn-domain/\{id\}.json` URI would be
* interpreted by clients as
* `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`
* for token type ID 0x4cce0.
*
* See {uri}.
*
* Because these URIs cannot be meaningfully represented by the {URI} event,
* this function emits no events.
*/
function _setURI(string memory newuri) internal virtual {
_uri = newuri;
}
/**
* @dev Creates `amount` tokens of token type `id`, and assigns them to `account`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `account` cannot be the zero address.
* - If `account` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function _mint(
address account,
uint256 id,
uint256 amount,
bytes memory data
) internal virtual {
require(account != address(0), "ERC1155: mint to the zero address");
address operator = _msgSender();
_beforeTokenTransfer(operator, address(0), account, _asSingletonArray(id), _asSingletonArray(amount), data);
_balances[id][account] += amount;
emit TransferSingle(operator, address(0), account, id, amount);
_doSafeTransferAcceptanceCheck(operator, address(0), account, id, amount, data);
}
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.
*
* Requirements:
*
* - `ids` and `amounts` must have the same length.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/
function _mintBatch(
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {
require(to != address(0), "ERC1155: mint to the zero address");
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
address operator = _msgSender();
_beforeTokenTransfer(operator, address(0), to, ids, amounts, data);
for (uint256 i = 0; i < ids.length; i++) {
_balances[ids[i]][to] += amounts[i];
}
emit TransferBatch(operator, address(0), to, ids, amounts);
_doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data);
}
/**
* @dev Destroys `amount` tokens of token type `id` from `account`
*
* Requirements:
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens of token type `id`.
*/
function _burn(
address account,
uint256 id,
uint256 amount
) internal virtual {
require(account != address(0), "ERC1155: burn from the zero address");
address operator = _msgSender();
_beforeTokenTransfer(operator, account, address(0), _asSingletonArray(id), _asSingletonArray(amount), "");
uint256 accountBalance = _balances[id][account];
require(accountBalance >= amount, "ERC1155: burn amount exceeds balance");
unchecked {
_balances[id][account] = accountBalance - amount;
}
emit TransferSingle(operator, account, address(0), id, amount);
}
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.
*
* Requirements:
*
* - `ids` and `amounts` must have the same length.
*/
function _burnBatch(
address account,
uint256[] memory ids,
uint256[] memory amounts
) internal virtual {
require(account != address(0), "ERC1155: burn from the zero address");
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
address operator = _msgSender();
_beforeTokenTransfer(operator, account, address(0), ids, amounts, "");
for (uint256 i = 0; i < ids.length; i++) {
uint256 id = ids[i];
uint256 amount = amounts[i];
uint256 accountBalance = _balances[id][account];
require(accountBalance >= amount, "ERC1155: burn amount exceeds balance");
unchecked {
_balances[id][account] = accountBalance - amount;
}
}
emit TransferBatch(operator, account, address(0), ids, amounts);
}
/**
* @dev Hook that is called before any token transfer. This includes minting
* and burning, as well as batched variants.
*
* The same hook is called on both single and batched variants. For single
* transfers, the length of the `id` and `amount` arrays will be 1.
*
* Calling conditions (for each `id` and `amount` pair):
*
* - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* of token type `id` will be transferred to `to`.
* - When `from` is zero, `amount` tokens of token type `id` will be minted
* for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens of token type `id`
* will be burned.
* - `from` and `to` are never both zero.
* - `ids` and `amounts` have the same, non-zero length.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {}
function _doSafeTransferAcceptanceCheck(
address operator,
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) private {
if (to.isContract()) {
try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {
if (response != IERC1155Receiver.onERC1155Received.selector) {
revert("ERC1155: ERC1155Receiver rejected tokens");
}
} catch Error(string memory reason) {
revert(reason);
} catch {
revert("ERC1155: transfer to non ERC1155Receiver implementer");
}
}
}
function _doSafeBatchTransferAcceptanceCheck(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) private {
if (to.isContract()) {
try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (
bytes4 response
) {
if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {
revert("ERC1155: ERC1155Receiver rejected tokens");
}
} catch Error(string memory reason) {
revert(reason);
} catch {
revert("ERC1155: transfer to non ERC1155Receiver implementer");
}
}
}
function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) {
uint256[] memory array = new uint256[](1);
array[0] = element;
return array;
}
}
// File: @openzeppelin/contracts/utils/Counters.sol
pragma solidity ^0.8.0;
/**
* @title Counters
* @author Matt Condon (@shrugs)
* @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number
* of elements in a mapping, issuing ERC721 ids, or counting request ids.
*
* Include with `using Counters for Counters.Counter;`
*/
library Counters {
struct Counter {
// This variable should never be directly accessed by users of the library: interactions must be restricted to
// the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
// this feature: see https://github.com/ethereum/solidity/issues/4637
uint256 _value; // default: 0
}
function current(Counter storage counter) internal view returns (uint256) {
return counter._value;
}
function increment(Counter storage counter) internal {
unchecked {
counter._value += 1;
}
}
function decrement(Counter storage counter) internal {
uint256 value = counter._value;
require(value > 0, "Counter: decrement overflow");
unchecked {
counter._value = value - 1;
}
}
function reset(Counter storage counter) internal {
counter._value = 0;
}
}
// File: contracts/FractionalNFT.sol
pragma solidity 0.8.10;
contract FractionalNFT is ERC1155, CustomOwnable {
using Counters for Counters.Counter;
Counters.Counter public _tokenIds;
// NFT name
string public name;
// NFT symbol
string public symbol;
// Mapping from token ID to token supply
mapping(uint256 => uint256) private tokenSupply;
// Mapping from token ID to token existence
mapping(uint256 => bool) private exists;
// Mapping from token ID to token URI
mapping(uint256 => string) private tokenURI;
/**
* @notice Initiates a Fractional NFT collection
* @param _name Name of the collection
* @param _symbol Symbol of the collection
* @param _owner Address of the contract owner
*/
constructor(
string memory _name,
string memory _symbol,
address _owner
) ERC1155("") CustomOwnable(_owner) {
name = _name;
symbol = _symbol;
}
/**
* @notice Mints a new token in the collection
* @param quantity Quantity of tokens to be created
* @param _uri Metadata URI of the new token
* @param _owner Address the token should be minted to
* @return token id of the new token created
*/
function createToken(
uint256 quantity,
string memory _uri,
address _owner
) public onlyOwner returns (uint256) {
_tokenIds.increment();
uint256 newItemId = _tokenIds.current();
require(!exists[newItemId], "INVALID_ID");
super._mint(_owner, newItemId, quantity, new bytes(0));
tokenURI[newItemId] = _uri;
tokenSupply[newItemId] += quantity;
return newItemId;
}
/**
* @notice Mints multiple new tokens in the collection
* @param quantities Quantities corresponding to the new tokens
* @param uris Metadata URIs of the new tokens
* @return token ids of the new tokens created
*/
function batchCreateTokens(
uint256[] memory quantities,
string[] memory uris
) public onlyOwner returns (uint256[] memory) {
uint256[] memory ids;
for (uint256 i = 0; i < quantities.length; i++) {
_tokenIds.increment();
ids[i] = _tokenIds.current();
}
require(ids.length == quantities.length, "MISMATCHED_ARRAY_LENGTHS");
super._mintBatch(msg.sender, ids, quantities, new bytes(0));
for (uint256 i = 0; i < ids.length; i++) {
tokenSupply[ids[i]] += quantities[i];
tokenURI[ids[i]] = uris[i];
}
return ids;
}
/**
* @notice Returns the URI of a token given its ID
* @param id ID of the token to query
* @return uri of the token or an empty string if it does not exist
*/
function uri(uint256 id) public view override returns (string memory) {
require(exists[id], "URI_QUERY_FOR_NON_EXISTENT_TOKEN");
return tokenURI[id];
}
/**
* @notice Returns the total quantity for a token ID
* @param id ID of the token to query
* @return amount of token in existence
*/
function totalSupply(uint256 id) public view returns (uint256) {
return tokenSupply[id];
}
}
// File: contracts/NFTMarket.sol
pragma solidity 0.8.10;
/// @author Velas Art Team
/// @title NFT Marketplace on Velas Blockchain
contract NFTMarket is ReentrancyGuard, Ownable, ERC1155Holder, ERC721Holder {
// STATE VARIABLES
uint16 constant HUNDRED = 10000;
IMarketPlaceFeeContract public feeContract;
address private creatorContractAddress;
mapping(address => uint256) public escrow;
mapping(address => uint256) public allowedToWithdraw;
mapping(address => Collection) public addressToCollection;
mapping(address => uint256[]) public tokenIdsInCollection;
mapping(address => Creator[]) public creatorFees;
mapping(address => mapping(uint256 => Ask[])) public asks;
mapping(address => mapping(uint256 => Bid[])) public bids;
mapping(address => mapping(uint256 => uint256)) public lastTradedPrice;
mapping(address => mapping(uint256 => SaleLog[])) public priceHistory;
address[] public collections;
address payable public beneficiary;
struct Collection {
bool isFractional;
bool mintedOnMarketPlace;
address createdBy;
string name;
string symbol;
string description;
string collectionSlug;
uint16 creatorRoyaltyInPercentage;
uint256 totalSupply;
uint256 listedTime;
uint256 volumeTraded;
}
struct Ask {
bool exists;
address seller;
uint256 price;
uint256 quantity;
uint256 timestamp;
}
struct Bid {
bool exists;
address buyer;
uint256 price;
uint256 quantity;
uint256 timestamp;
}
struct Creator {
uint16 shareInPercentage;
address payable creator;
}
struct UserAsk {
address nftContract;
uint256 tokenId;
uint256 askIndex;
uint256 price;
uint256 quantity;
uint256 timestamp;
}
struct UserBid {
address nftContract;
uint256 tokenId;
uint256 bidIndex;
uint256 price;
uint256 quantity;
uint256 timestamp;
}
struct SaleLog {
address seller;
address buyer;
uint256 price;
uint256 timestamp;
}
// EVENTS
event CollectionCreated(
uint256 collectionId,
address _nftContract,
string _name,
string _symbol,
uint256 timestamp
);
event AskCreated(
address indexed nft,
uint256 indexed tokenID,
uint256 price,
address indexed seller,
uint256 quantity
);
event AskDeleted(
address indexed nft,
uint256 indexed tokenID,
address indexed seller,
uint256 price
);
event AskAccepted(
address indexed nft,
uint256 indexed tokenID,
uint256 price,
uint256 quantity,
address indexed buyer
);
event BidCreated(
address indexed nft,
uint256 indexed tokenID,
address indexed buyer,
uint256 price,
uint256 quantity
);
event BidDeleted(
address indexed nft,
uint256 indexed tokenID,
address indexed buyer,
uint256 price
);
event BidAccepted(
address indexed nft,
uint256 indexed tokenID,
uint256 price,
uint256 quantity,
address indexed seller
);
event BidPayment(bool isCredit, address indexed user, Bid bid);
event AskPayment(bool isCredit, address indexed user, Ask ask);
event RoyaltyPayment(
address indexed user,
uint256 amount,
address indexed nftContract,
uint256 tokenId
);
event Withdrawal(address indexed payee, uint256 amount);
// CONSTRUCTOR
/**
* @notice Initiates the contract with feeContract and creatorContractAddress
* @param _feeContract The instance of MarketPlaceFeeContract which is used by the marketplace for fee calculations
* @param _creatorContractAddress The collection creator contract used by the marketplace
* @param _beneficiary The beneficiary of Marketplace Fees
*/
constructor(
IMarketPlaceFeeContract _feeContract,
address _creatorContractAddress,
address payable _beneficiary
) {
feeContract = _feeContract;
creatorContractAddress = _creatorContractAddress;
beneficiary = _beneficiary;
}
// EXTERNAL FUNCTIONS
/**
* @notice Imports a verified contract with creator royalties - Only callable by the creatorContract
* @param _nftContract The address of NFT contract imported
* @param _name Name of the NFT Contract
* @param _symbol Symbol of the NFT Contract
* @param _description Description of the NFT Contract
* @param _collectionSlug Slug of the collection
* @param _isFractional True if the contract is ERC1155 compatible and False if ERC721
* @param _creatorRoyaltyInPercentage Creator Royalty in percentage scaled to 10^2
* @param _creators Array of creator addresses that share the royalty
* @param _percentages Array of percentages corresponding to the creators above
* @param _createdBy Creator of the contract
*/
function createCollection(
address _nftContract,
string memory _name,
string memory _symbol,
string memory _description,
string memory _collectionSlug,
bool _isFractional,
uint16 _creatorRoyaltyInPercentage,
address payable[] memory _creators,
uint16[] memory _percentages,
address _createdBy
) public {
require(
msg.sender == creatorContractAddress || msg.sender == owner(),
"UNAUTHORIZED"
);
require(
addressToCollection[_nftContract].listedTime == 0,
"EXISTING_COLLECTION"
); // Checks if collection already exists
uint16 totalPercentage;
for (uint256 i = 0; i < _percentages.length; i++) {
totalPercentage += _percentages[i];
}
require(
totalPercentage == 10000 || totalPercentage == 0,
"TOTAL_PERCENTAGE_NOT_VALID"
);
Collection memory _tempCollection;
uint256 totalSupply;
if (msg.sender == creatorContractAddress) {
totalSupply = 0;
_tempCollection.mintedOnMarketPlace = true;
} else {
try IERC721Enumerable(_nftContract).totalSupply() returns (
uint256 _totalSupply
) {
totalSupply = _totalSupply;
} catch {
totalSupply = 0;
}
_tempCollection.mintedOnMarketPlace = false;
}
_tempCollection.name = _name;
_tempCollection.symbol = _symbol;
_tempCollection.description = _description;
_tempCollection.collectionSlug = _collectionSlug;
_tempCollection.isFractional = _isFractional;
_tempCollection.totalSupply = totalSupply;
_tempCollection.listedTime = block.timestamp;
_tempCollection.createdBy = _createdBy;
_tempCollection
.creatorRoyaltyInPercentage = _creatorRoyaltyInPercentage;
addressToCollection[_nftContract] = _tempCollection;
collections.push(_nftContract);
addCreatorFees(_nftContract, _creators, _percentages);
emit CollectionCreated(
collections.length, // array index will be the collectionId
_nftContract,
_name,
_symbol,
block.timestamp
);
}
/**
* @notice Creates an ask for (`nft`, `tokenID`) tuple for `price` and `quantity`
* @dev Creating an ask requires msg.sender to have at least one qty of (`nft`, `tokenID`)
* @param _nftContract An array of ERC-721 and / or ERC-1155 addresses
* @param _tokenId Token Ids of the NFTs msg.sender wishes to sell
* @param _price Prices at which the seller is willing to sell the NFTs
* @param _quantity Number of tokens the seller is willing to sell. 1 if the NFT is ERC721 standard
*/
function ask(
address[] memory _nftContract,
uint256[] memory _tokenId,
uint256[] memory _price,
uint256[] memory _quantity
) public {
require(
_nftContract.length == _tokenId.length &&
_nftContract.length == _price.length &&
_nftContract.length == _quantity.length,
"ARRAY_LENGTHS_MISMATCH"
);
for (uint256 i = 0; i < _nftContract.length; i++) {
address nftContract = _nftContract[i];
uint256 tokenId = _tokenId[i];
uint256 price = _price[i];
uint256 quantity = _quantity[i];
require(price > 0, "PRICE_LT_ZERO");
require(
quantityOf(nftContract, msg.sender, tokenId) > 0,
"NOT_OWNER_OF_TOKEN"
);
require(isApproved(_nftContract[i]), "NOT_APPROVED_FOR_TRANSFER");
if (!tokenIdExists(nftContract, tokenId)) {
tokenIdsInCollection[nftContract].push(tokenId);
}
// There can be multiple asks for a tokenId in case of ERC1155 tokens
asks[nftContract][tokenId].push(
Ask({
exists: true,
seller: msg.sender,
price: price,
quantity: quantity,
timestamp: block.timestamp
})
);
bool success = safeTransferFrom_(
nftContract,
tokenId,
msg.sender,
address(this),
quantity,
new bytes(0)
);
require(success, "REVERT_NFT_NOT_SENT");
emit AskCreated({
nft: address(nftContract),
tokenID: tokenId,
price: price,
seller: msg.sender,
quantity: quantity
});
}
}
/**
* @notice Creates a bid on (`nft`, `tokenID`) tuple for `price`.
* @dev Creating a bid requires msg.sender to pay the (bid amount - escrow balance) to the contract
* @param _nftContract An array of ERC-721 and / or ERC-1155 addresses
* @param _tokenId Token Ids of the NFTs msg.sender wishes to buy
* @param _price Prices at which the buyer is willing to buy the NFTs
* @param _quantity Number of tokens the buyer is willing to buy. 1 if the NFT is ERC721 standard
*/
function bid(
address[] memory _nftContract,
uint256[] memory _tokenId,
uint256[] memory _price,
uint256[] memory _quantity
) public payable nonReentrant {
require(
_nftContract.length == _tokenId.length &&
_nftContract.length == _price.length &&
_nftContract.length == _quantity.length,
"ARRAY_LENGTHS_MISMATCH"
);
uint256 totalPrice;
for (uint256 i = 0; i < _nftContract.length; i++) {
address nftContract = _nftContract[i];
uint256 tokenId = _tokenId[i];
uint256 price = _price[i];
uint256 quantity = _quantity[i];
if (!tokenIdExists(nftContract, tokenId)) {
tokenIdsInCollection[nftContract].push(tokenId);
}
bids[nftContract][tokenId].push(
Bid({
exists: true,
buyer: msg.sender,
price: price,
quantity: quantity,
timestamp: block.timestamp
})
);
emit BidCreated({
nft: nftContract,
tokenID: tokenId,
buyer: msg.sender,
price: price,
quantity: quantity
});
totalPrice += price * quantity;
emit BidPayment(
false,
msg.sender,
Bid({
exists: true,
buyer: msg.sender,
price: price,
quantity: quantity,
timestamp: block.timestamp
})
);
}
require(msg.value >= totalPrice, "REVERT_INSUFFICIENT_ETHER");
escrow[msg.sender] += (totalPrice);
payable(msg.sender).transfer(msg.value - totalPrice);
}
/**
* @notice Cancels ask(s) that the seller previously created
* @param _nftContract An array of ERC-721 and / or ERC-1155 addresses
* @param _tokenId Token Ids of the NFTs msg.sender wishes to cancel the asks on
* @param _askIndex Index of this particular ask in the asks array
*/
function cancelAsk(
address[] memory _nftContract,
uint256[] memory _tokenId,
uint256[] memory _askIndex
) public {
for (uint256 i = 0; i < _nftContract.length; i++) {
address nftContract = _nftContract[i];
uint256 tokenId = _tokenId[i];
uint256 askIndex = _askIndex[i];
address seller = asks[nftContract][tokenId][askIndex].seller;
uint256 price = asks[nftContract][tokenId][askIndex].price;
uint256 quantity = asks[nftContract][tokenId][askIndex].quantity;
require(seller == msg.sender, "REVERT_NOT_A_CREATOR_OF_ASK");
bool success = safeTransferFrom_(
nftContract,
tokenId,
address(this),
msg.sender,
quantity,
new bytes(0)
);
require(success, "TRANSFER_FAILED");
delete asks[nftContract][tokenId][askIndex];
emit AskDeleted({
nft: nftContract,
tokenID: tokenId,
seller: seller,
price: price
});
}
}
/**
* @notice Cancels bid(s) that the msg.sender previously created
* @param _nftContract An array of ERC-721 and / or ERC-1155 addresses
* @param _tokenId Token Ids of the NFTs msg.sender wishes to cancel the bids on
* @param _bidIndex Index of this particular bid in the bids array
*/
function cancelBid(
address[] memory _nftContract,
uint256[] memory _tokenId,
uint256[] memory _bidIndex
) public nonReentrant {
for (uint256 i = 0; i < _nftContract.length; i++) {
address nftAddress = _nftContract[i];
uint256 tokenId = _tokenId[i];
uint256 bidIndex = _bidIndex[i];
address buyer = bids[nftAddress][tokenId][bidIndex].buyer;
uint256 price = bids[nftAddress][tokenId][bidIndex].price;
uint256 quantity = bids[nftAddress][tokenId][bidIndex].quantity;
require(buyer == msg.sender, "REVERT_NOT_A_CREATOR_OF_BID");
escrow[msg.sender] -= (price * quantity);
emit BidPayment(
true,
msg.sender,
bids[nftAddress][tokenId][bidIndex]
);
delete bids[nftAddress][tokenId][bidIndex];
emit BidDeleted({
nft: nftAddress,
tokenID: tokenId,
buyer: buyer,
price: price
});
payable(msg.sender).transfer(price * quantity);
}
}
/**
* @notice Seller placed ask(s), you (buyer) are fine with the terms. You accept
* their ask by sending the required msg.value and indicating the id of the
* token(s) you are purchasing.
*
* @param _nftContract An array of ERC-721 and / or ERC-1155 addresses
* @param _tokenId Token Ids of the NFTs msg.sender wishes to accept the asks on
* @param _quantity Number of tokens the buyer is willing to buy. 1 if the NFT is ERC721 standard
* @param _askIndex Index of this particular ask in the asks array
*/
function acceptAsk(
address[] memory _nftContract,
uint256[] memory _tokenId,
uint256[] memory _quantity,
uint256[] memory _askIndex
) public payable nonReentrant {
require(
_nftContract.length == _tokenId.length &&
_nftContract.length == _askIndex.length &&
_nftContract.length == _quantity.length,
"ARRAY_LENGTHS_MISMATCH"
);
uint256 totalPrice;
for (uint256 i = 0; i < _nftContract.length; i++) {
address nftContract = _nftContract[i];
uint256 tokenId = _tokenId[i];
uint256 askIndex = _askIndex[i];
uint256 quantity = _quantity[i];
bool exists = asks[nftContract][tokenId][askIndex].exists;
address seller = asks[nftContract][tokenId][askIndex].seller;
uint256 price = asks[nftContract][tokenId][askIndex].price;
require(exists, "REVERT_ASK_DOES_NOT_EXIST");
require(seller != msg.sender, "REVERT_CANT_ACCEPT_OWN_ASK");
require(
quantity <= asks[nftContract][tokenId][askIndex].quantity,
"QUANTITY_EXCEEDS_ASK"
);
totalPrice += (price * quantity);
uint256 creatorRoyalty = payRoyalty(
nftContract,
price,
quantity,
tokenId
);
allowedToWithdraw[beneficiary] += feeContract._collectMarketFee(
seller,
price * quantity
);
emit AskPayment(true, seller, asks[nftContract][tokenId][askIndex]);
// Quantity will reduce in case of ERC1155 tokens and deleted in case of ERC721 tokens
if (quantity < asks[nftContract][tokenId][askIndex].quantity) {
asks[nftContract][tokenId][askIndex].quantity -= quantity;
} else {
delete asks[nftContract][tokenId][askIndex];
}
addressToCollection[nftContract].volumeTraded += (price * quantity);
lastTradedPrice[nftContract][tokenId] = price;
SaleLog memory tempLog;
tempLog.price = price;
tempLog.timestamp = block.timestamp;
tempLog.seller = seller;
tempLog.buyer = msg.sender;
priceHistory[nftContract][tokenId].push(tempLog);
bool success = safeTransferFrom_(
nftContract,
tokenId,
address(this),
msg.sender,
quantity,
new bytes(0)
);
require(success, "REVERT_NFT_NOT_SENT");
emit AskAccepted({
nft: nftContract,
tokenID: tokenId,
price: price,
quantity: quantity,
buyer: msg.sender
});
emit AskPayment(
false,
msg.sender,
asks[nftContract][tokenId][askIndex]
);
payable(seller).transfer(
(price * quantity) -
feeContract._collectMarketFee(seller, price * quantity) -
creatorRoyalty
);
}
require(msg.value >= totalPrice, "REVERT_INSUFFICIENT_ETHER");
payable(msg.sender).transfer(msg.value - totalPrice);
}
/**
* @notice You are the owner of the NFTs, someone submitted the bids on them.
* You accept one or more of these bids.
*
* @param _nftContract An array of ERC-721 and / or ERC-1155 addresses
* @param _tokenId Token Ids of the NFTs msg.sender wishes to accept the bids on
* @param _quantity Number of tokens the buyer is willing to buy. 1 if the NFT is ERC721 standard
* @param _bidIndex Index of this particular bid in the bids array
*/
function acceptBid(
address[] memory _nftContract,
uint256[] memory _tokenId,
uint256[] memory _quantity,
uint256[] memory _bidIndex
) public nonReentrant {
require(
_nftContract.length == _tokenId.length &&
_nftContract.length == _bidIndex.length &&
_nftContract.length == _quantity.length,
"ARRAY_LENGTHS_MISMATCH"
);
for (uint256 i = 0; i < _nftContract.length; i++) {
require(
quantityOf(_nftContract[i], msg.sender, _tokenId[i]) > 0,
"REVERT_NOT_OWNER_OF_TOKEN_ID"
);
address nftContract = _nftContract[i];
uint256 tokenId = _tokenId[i];
uint256 bidIndex = _bidIndex[i];
uint256 quantity = _quantity[i];
uint256 price = bids[nftContract][tokenId][bidIndex].price;
address buyer = bids[nftContract][tokenId][bidIndex].buyer;
require(isApproved(_nftContract[i]), "NOT_APPROVED_FOR_TRANSFER");
uint256 creatorRoyalty = payRoyalty(
nftContract,
price,
quantity,
tokenId
);
allowedToWithdraw[beneficiary] += feeContract._collectMarketFee(
msg.sender,
price * quantity
);
emit BidPayment(
true,
msg.sender,
bids[nftContract][tokenId][bidIndex]
);
// delete ask if ERC721
if (!addressToCollection[nftContract].isFractional) {
for (
uint256 j = 0;
j < asks[nftContract][tokenId].length;
j++
) {
Ask memory _ask = asks[nftContract][tokenId][j];
if (_ask.seller == msg.sender) {
delete asks[nftContract][tokenId][j];
}
}
}
Bid memory tempBid = bids[nftContract][tokenId][bidIndex]; // For event emit
// Quantity will reduce in case of ERC1155 tokens and deleted in case of ERC721 tokens
if (quantity < bids[nftContract][tokenId][bidIndex].quantity) {
bids[nftContract][tokenId][bidIndex].quantity -= quantity;
} else {
delete bids[nftContract][tokenId][bidIndex];
}
addressToCollection[nftContract].volumeTraded += price * quantity;
lastTradedPrice[nftContract][tokenId] = price;
SaleLog memory tempLog;
tempLog.price = price;
tempLog.timestamp = block.timestamp;
tempLog.seller = msg.sender;
tempLog.buyer = buyer;
priceHistory[nftContract][tokenId].push(tempLog);
uint256 balancePayable = price * quantity;
require(escrow[buyer] >= balancePayable, "LOW_BUYER_BALANCE");
escrow[buyer] -= balancePayable;
bool success = safeTransferFrom_(
nftContract,
tokenId,
msg.sender,
buyer,
quantity,
new bytes(0)
);
require(success, "REVERT_NFT_NOT_SENT");
emit BidPayment(false, buyer, tempBid);
emit BidAccepted({
nft: nftContract,
tokenID: tokenId,
price: price,
quantity: quantity,
seller: msg.sender
});
payable(msg.sender).transfer(
(price * quantity) -
feeContract._collectMarketFee(
msg.sender,
price * quantity
) -
creatorRoyalty
);
}
}
/**
* @notice Withdrawal of accumulated funds from escrow account
* @param amount Amount to be withdrawn
*/
function withdraw(int256 amount) public nonReentrant {
// Enter amount = -1 for MAX withdrawal
uint256 transferAmount;
if (amount == -1) {
transferAmount = allowedToWithdraw[msg.sender];
} else {
transferAmount = uint256(amount);
}
require(
transferAmount <= allowedToWithdraw[msg.sender],
"AMOUNT_EXCEEDS_BALANCE"
);
allowedToWithdraw[msg.sender] -= transferAmount;
payable(address(msg.sender)).transfer(transferAmount);
emit Withdrawal(msg.sender, transferAmount);
}
/**
* @notice Change the Collection creator and Fee contract address
* @dev Can only be called by the owner of the marketplace
* @param _newCreatorContract Address of the new creatorContract
* @param _newFeeContract Address of the new feeContract
*/
function changeCreatorAndFeeContract(
address _newCreatorContract,
address _newFeeContract,
address payable _beneficiary
) public onlyOwner {
creatorContractAddress = _newCreatorContract;
feeContract = IMarketPlaceFeeContract(_newFeeContract);
beneficiary = _beneficiary;
}
/**
* @notice Rejects a Creator Royalty payment request
* @dev Can only be called by the owner of the marketplace
* @param _nftContract Address of the NFT collection
* @param _newOwner Address of the new owner of the collection
*/
function changeCollectionOwner(address _nftContract, address _newOwner)
public
onlyOwner
{
addressToCollection[_nftContract].createdBy = _newOwner;
}
/**
* @notice Returns the floorPrice of a collection
* @param nftContract Address of the collection
* @return floor price of a collection
*/
function floorPrice(address nftContract) public view returns (uint256) {
uint256 _floorPrice;
uint256[] memory _tokenIds = tokenIdsInCollection[nftContract];
if (_tokenIds.length == 0) {
return 0;
} else {
_floorPrice = asks[nftContract][_tokenIds[0]][0].price;
}
for (uint256 i = 0; i < _tokenIds.length; i++) {
Ask[] memory askArray = asks[nftContract][_tokenIds[i]];
for (uint256 j = 0; j < askArray.length; j++) {
if (askArray[j].price < _floorPrice || _floorPrice == 0) {
_floorPrice = askArray[j].price;
}
}
}
return _floorPrice;
}
/**
* @notice Returns the tokenIds in a collection
* @param nftContract Address of the collection
* @return tokenIds array of tokenIds
*/
function fetchTokensInCollection(address nftContract)
public
view
returns (uint256[] memory tokenIds)
{
return tokenIdsInCollection[nftContract];
}
// PUBLIC FUNCTIONS
/**
* @notice Returns the list of collections in the marketplace
* @return collectionsList An array of collections
*/
function fetchCollectionsList()
public
view
returns (address[] memory collectionsList)
{
return collections;
}
/**
* @notice Returns all NFTs held by the user
* @param _user User address whose NFTs are requested
* @return userNFTAddresses userNFTIds - An array of collections and the corresponding tokenIds owned by the user
*/
function fetchUserNFTs(address _user)
public
view
returns (address[] memory userNFTAddresses, uint256[] memory userNFTIds)
{
uint256 counter;
for (uint256 i = 0; i < collections.length; i++) {
if (collections[i] == address(0)) {
continue;
}
address tempCollectionAddress = collections[i];
for (
uint256 j = 0;
j < tokenIdsInCollection[tempCollectionAddress].length;
j++
) {
if (addressToCollection[tempCollectionAddress].isFractional) {
if (
IERC1155(tempCollectionAddress).balanceOf(
_user,
tokenIdsInCollection[tempCollectionAddress][j]
) > 0
) {
userNFTAddresses[counter] = tempCollectionAddress;
userNFTIds[counter] = tokenIdsInCollection[
tempCollectionAddress
][j];
counter++;
}
} else {
if (
ERC721(tempCollectionAddress).ownerOf(
tokenIdsInCollection[tempCollectionAddress][j]
) == msg.sender
) {
userNFTAddresses[counter] = tempCollectionAddress;
userNFTIds[counter] = tokenIdsInCollection[
tempCollectionAddress
][j];
counter++;
}
}
}
}
}
/**
* @notice Returns all Asks and Bids for a token
* @param nftContract nft contract address whose Asks and Bids are requested
* @param tokenId token id whose Asks and Bids are requested
* @return Asks Bids - Asks and Bids for a token id
*/
function fetchTokenAsksAndBids(address nftContract, uint256 tokenId)
public
view
returns (Ask[] memory Asks, Bid[] memory Bids)
{
return (asks[nftContract][tokenId], bids[nftContract][tokenId]);
}
/**
* @notice Returns the lowest ask for a token
* @param nftContract NFT address
* @param tokenId id of the token
* @return Lowest ask and corresponding quantity
*/
function lowestAsk(address nftContract, uint256 tokenId)
public
view
returns (uint256, uint256)
{
uint256 lowestAskPrice;
uint256 correspondingQuantity;
Ask[] memory currentAsk = asks[nftContract][tokenId];
if (currentAsk.length == 0) {
return (0, 0);
} else {
lowestAskPrice = currentAsk[0].price;
correspondingQuantity = currentAsk[0].quantity;
}
for (uint256 i = 0; i < currentAsk.length; i++) {
if (currentAsk[i].price < lowestAskPrice || lowestAskPrice == 0) {
lowestAskPrice = currentAsk[i].price;
correspondingQuantity = currentAsk[i].quantity;
}
if (currentAsk[i].price == lowestAskPrice || lowestAskPrice == 0) {
correspondingQuantity += currentAsk[i].quantity;
}
}
return (lowestAskPrice, correspondingQuantity);
}
/**
* @notice Returns the highest bid for a token
* @param nftContract NFT address
* @param tokenId id of the token
* @return Highest bid and corresponding quantity
*/
function highestBid(address nftContract, uint256 tokenId)
public
view
returns (uint256, uint256)
{
uint256 highestBidPrice;
uint256 correspondingQuantity;
Bid[] memory currentBid = bids[nftContract][tokenId];
if (currentBid.length == 0) {
return (0, 0);
} else {
highestBidPrice = currentBid[0].price;
correspondingQuantity = currentBid[0].quantity;
}
for (uint256 i = 0; i < currentBid.length; i++) {
if (currentBid[i].price > highestBidPrice || highestBidPrice == 0) {
highestBidPrice = currentBid[i].price;
correspondingQuantity = currentBid[i].quantity;
}
if (
currentBid[i].price == highestBidPrice || highestBidPrice == 0
) {
correspondingQuantity += currentBid[i].quantity;
}
}
return (highestBidPrice, correspondingQuantity);
}
/**
* @notice Returns the creators for a collection
* @param nftContract NFT address
* @return creators array
*/
function fetchCreators(address nftContract)
public
view
returns (Creator[] memory creators)
{
return creatorFees[nftContract];
}
/**
* @notice Returns if the marketplace is approved by the msg.sender for transfers
* @param nftContract Address of ERC721 or ERC1155 contract
* @return approved True if approved and False if not
*/
function isApproved(address nftContract)
public
view
returns (bool approved)
{
return IERC721(nftContract).isApprovedForAll(msg.sender, address(this));
}
/**
* @notice Returns the price history of the tokenId
* @param _nftContract Address of the collection
* @param _tokenId Token Id of the requested token
* @return Array of price history for the token
*/
function fetchPriceHistory(address _nftContract, uint256 _tokenId)
public
view
returns (SaleLog[] memory)
{
return priceHistory[_nftContract][_tokenId];
}
// INTERNAL FUNCTIONS
/**
* @notice Transfers the NFT tokenID from to
* @dev safeTransferFrom_ name to avoid collision with the interface signature definitions. The reason it is implemented the way it is,
* is because some NFT contracts implement both the 721 and 1155 standard at the same time. Sometimes, 721 or 1155 function does not work.
* So instead of relying on the user's input, or asking the contract what interface it implements, it is best to just make a good assumption
* about what NFT type it is (here we guess it is 721 first), and if that fails, we use the 1155 function to tranfer the NFT.
* @param nftContract NFT address
* @param from Source address
* @param to Target address
* @param tokenId ID of the token type
* @param quantity Quantity of tokens
* @param data Additional data with no specified format, MUST be sent unaltered in call to `onERC1155Received` on `_to`
*/
function safeTransferFrom_(
address nftContract,
uint256 tokenId,
address from,
address to,
uint256 quantity,
bytes memory data
) internal returns (bool) {
// most are 721s, so we assume that that is what the NFT type is
try IERC721(nftContract).safeTransferFrom(from, to, tokenId, data) {
return true;
// on fail, use 1155s format
} catch (bytes memory) {
try
IERC1155(nftContract).safeTransferFrom(
from,
to,
tokenId,
quantity,
data
)
{
return true;
} catch (bytes memory) {
return false;
}
}
}
/**
* @notice Determines if potentialOwner is in fact an owner of at least 1 qty of NFT token ID.
* @param nftContract NFT address
* @param potentialOwner suspected owner of the NFT token ID
* @param tokenId id of the token
* @return quantity of held token, possibly zero
*/
function quantityOf(
address nftContract,
address potentialOwner,
uint256 tokenId
) internal view returns (uint256) {
try IERC721(nftContract).ownerOf(tokenId) returns (address owner) {
if (owner == potentialOwner) {
return 1;
} else {
return 0;
}
} catch (bytes memory) {
try
IERC1155(nftContract).balanceOf(potentialOwner, tokenId)
returns (uint256 amount) {
return amount;
} catch (bytes memory) {
return 0;
}
}
}
// PRIVATE FUNCTIONS
/**
* @notice Adds creator royalties to creators of an NFT collection
* @param _nftContract NFT address
* @param _creators Array of creator addresses that share the royalty
* @param _percentages Array of percentages corresponding to the creators above
*/
function addCreatorFees(
address _nftContract,
address payable[] memory _creators,
uint16[] memory _percentages
) private {
for (uint256 j = 0; j < _creators.length; j++) {
Creator memory _creatorFees;
_creatorFees.creator = _creators[j];
_creatorFees.shareInPercentage = _percentages[j];
creatorFees[_nftContract].push(_creatorFees);
}
}
/**
* @notice Calculates royalty fees for creators of a collection during acceptAsk or acceptBid operations
* @param _nftContract NFT address
* @param _price Price of the token
* @param _quantity Quantity of the token
* @param _tokenId Token Id of the NFT
* @return Royalty fees calculated
*/
function payRoyalty(
address _nftContract,
uint256 _price,
uint256 _quantity,
uint256 _tokenId
) private returns (uint256) {
uint256 creatorRoyalty;
if (addressToCollection[_nftContract].creatorRoyaltyInPercentage > 0) {
for (uint256 j = 0; j < creatorFees[_nftContract].length; j++) {
uint256 total = _price * _quantity;
uint256 share = (((total *
addressToCollection[_nftContract]
.creatorRoyaltyInPercentage) / HUNDRED) *
creatorFees[_nftContract][j].shareInPercentage) / HUNDRED;
allowedToWithdraw[
creatorFees[_nftContract][j].creator
] += share;
creatorRoyalty += share;
emit RoyaltyPayment(
creatorFees[_nftContract][j].creator,
share,
_nftContract,
_tokenId
);
}
}
return creatorRoyalty;
}
/**
* @notice Checks if a tokenId exists within a collection
* @param _nftContract NFT contract address
* @param _tokenId Token Id of the NFT
* @return True if exists and False if not
*/
function tokenIdExists(address _nftContract, uint256 _tokenId)
private
view
returns (bool)
{
for (
uint256 i = 0;
i < tokenIdsInCollection[_nftContract].length;
i++
) {
if (tokenIdsInCollection[_nftContract][i] == _tokenId) {
return true;
}
}
return false;
}
/**
* @notice Deletes a collection from the contract
* @param _nftContract NFT contract address
*/
function deleteCollection(address _nftContract) external onlyOwner {
Collection memory _tempCollection;
addressToCollection[_nftContract] = _tempCollection;
for (uint256 i = 0; i < collections.length; i++) {
if (collections[i] == _nftContract) {
delete collections[i];
break;
}
}
}
}
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_feeContract","internalType":"contract IMarketPlaceFeeContract"},{"type":"address","name":"_creatorContractAddress","internalType":"address"},{"type":"address","name":"_beneficiary","internalType":"address payable"}]},{"type":"event","name":"AskAccepted","inputs":[{"type":"address","name":"nft","internalType":"address","indexed":true},{"type":"uint256","name":"tokenID","internalType":"uint256","indexed":true},{"type":"uint256","name":"price","internalType":"uint256","indexed":false},{"type":"uint256","name":"quantity","internalType":"uint256","indexed":false},{"type":"address","name":"buyer","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"AskCreated","inputs":[{"type":"address","name":"nft","internalType":"address","indexed":true},{"type":"uint256","name":"tokenID","internalType":"uint256","indexed":true},{"type":"uint256","name":"price","internalType":"uint256","indexed":false},{"type":"address","name":"seller","internalType":"address","indexed":true},{"type":"uint256","name":"quantity","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"AskDeleted","inputs":[{"type":"address","name":"nft","internalType":"address","indexed":true},{"type":"uint256","name":"tokenID","internalType":"uint256","indexed":true},{"type":"address","name":"seller","internalType":"address","indexed":true},{"type":"uint256","name":"price","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"AskPayment","inputs":[{"type":"bool","name":"isCredit","internalType":"bool","indexed":false},{"type":"address","name":"user","internalType":"address","indexed":true},{"type":"tuple","name":"ask","internalType":"struct NFTMarket.Ask","indexed":false,"components":[{"type":"bool","name":"exists","internalType":"bool"},{"type":"address","name":"seller","internalType":"address"},{"type":"uint256","name":"price","internalType":"uint256"},{"type":"uint256","name":"quantity","internalType":"uint256"},{"type":"uint256","name":"timestamp","internalType":"uint256"}]}],"anonymous":false},{"type":"event","name":"BidAccepted","inputs":[{"type":"address","name":"nft","internalType":"address","indexed":true},{"type":"uint256","name":"tokenID","internalType":"uint256","indexed":true},{"type":"uint256","name":"price","internalType":"uint256","indexed":false},{"type":"uint256","name":"quantity","internalType":"uint256","indexed":false},{"type":"address","name":"seller","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"BidCreated","inputs":[{"type":"address","name":"nft","internalType":"address","indexed":true},{"type":"uint256","name":"tokenID","internalType":"uint256","indexed":true},{"type":"address","name":"buyer","internalType":"address","indexed":true},{"type":"uint256","name":"price","internalType":"uint256","indexed":false},{"type":"uint256","name":"quantity","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"BidDeleted","inputs":[{"type":"address","name":"nft","internalType":"address","indexed":true},{"type":"uint256","name":"tokenID","internalType":"uint256","indexed":true},{"type":"address","name":"buyer","internalType":"address","indexed":true},{"type":"uint256","name":"price","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"BidPayment","inputs":[{"type":"bool","name":"isCredit","internalType":"bool","indexed":false},{"type":"address","name":"user","internalType":"address","indexed":true},{"type":"tuple","name":"bid","internalType":"struct NFTMarket.Bid","indexed":false,"components":[{"type":"bool","name":"exists","internalType":"bool"},{"type":"address","name":"buyer","internalType":"address"},{"type":"uint256","name":"price","internalType":"uint256"},{"type":"uint256","name":"quantity","internalType":"uint256"},{"type":"uint256","name":"timestamp","internalType":"uint256"}]}],"anonymous":false},{"type":"event","name":"CollectionCreated","inputs":[{"type":"uint256","name":"collectionId","internalType":"uint256","indexed":false},{"type":"address","name":"_nftContract","internalType":"address","indexed":false},{"type":"string","name":"_name","internalType":"string","indexed":false},{"type":"string","name":"_symbol","internalType":"string","indexed":false},{"type":"uint256","name":"timestamp","internalType":"uint256","indexed":false}],"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":"event","name":"RoyaltyPayment","inputs":[{"type":"address","name":"user","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false},{"type":"address","name":"nftContract","internalType":"address","indexed":true},{"type":"uint256","name":"tokenId","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Withdrawal","inputs":[{"type":"address","name":"payee","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"payable","outputs":[],"name":"acceptAsk","inputs":[{"type":"address[]","name":"_nftContract","internalType":"address[]"},{"type":"uint256[]","name":"_tokenId","internalType":"uint256[]"},{"type":"uint256[]","name":"_quantity","internalType":"uint256[]"},{"type":"uint256[]","name":"_askIndex","internalType":"uint256[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"acceptBid","inputs":[{"type":"address[]","name":"_nftContract","internalType":"address[]"},{"type":"uint256[]","name":"_tokenId","internalType":"uint256[]"},{"type":"uint256[]","name":"_quantity","internalType":"uint256[]"},{"type":"uint256[]","name":"_bidIndex","internalType":"uint256[]"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"isFractional","internalType":"bool"},{"type":"bool","name":"mintedOnMarketPlace","internalType":"bool"},{"type":"address","name":"createdBy","internalType":"address"},{"type":"string","name":"name","internalType":"string"},{"type":"string","name":"symbol","internalType":"string"},{"type":"string","name":"description","internalType":"string"},{"type":"string","name":"collectionSlug","internalType":"string"},{"type":"uint16","name":"creatorRoyaltyInPercentage","internalType":"uint16"},{"type":"uint256","name":"totalSupply","internalType":"uint256"},{"type":"uint256","name":"listedTime","internalType":"uint256"},{"type":"uint256","name":"volumeTraded","internalType":"uint256"}],"name":"addressToCollection","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"allowedToWithdraw","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"ask","inputs":[{"type":"address[]","name":"_nftContract","internalType":"address[]"},{"type":"uint256[]","name":"_tokenId","internalType":"uint256[]"},{"type":"uint256[]","name":"_price","internalType":"uint256[]"},{"type":"uint256[]","name":"_quantity","internalType":"uint256[]"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"exists","internalType":"bool"},{"type":"address","name":"seller","internalType":"address"},{"type":"uint256","name":"price","internalType":"uint256"},{"type":"uint256","name":"quantity","internalType":"uint256"},{"type":"uint256","name":"timestamp","internalType":"uint256"}],"name":"asks","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address payable"}],"name":"beneficiary","inputs":[]},{"type":"function","stateMutability":"payable","outputs":[],"name":"bid","inputs":[{"type":"address[]","name":"_nftContract","internalType":"address[]"},{"type":"uint256[]","name":"_tokenId","internalType":"uint256[]"},{"type":"uint256[]","name":"_price","internalType":"uint256[]"},{"type":"uint256[]","name":"_quantity","internalType":"uint256[]"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"exists","internalType":"bool"},{"type":"address","name":"buyer","internalType":"address"},{"type":"uint256","name":"price","internalType":"uint256"},{"type":"uint256","name":"quantity","internalType":"uint256"},{"type":"uint256","name":"timestamp","internalType":"uint256"}],"name":"bids","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"cancelAsk","inputs":[{"type":"address[]","name":"_nftContract","internalType":"address[]"},{"type":"uint256[]","name":"_tokenId","internalType":"uint256[]"},{"type":"uint256[]","name":"_askIndex","internalType":"uint256[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"cancelBid","inputs":[{"type":"address[]","name":"_nftContract","internalType":"address[]"},{"type":"uint256[]","name":"_tokenId","internalType":"uint256[]"},{"type":"uint256[]","name":"_bidIndex","internalType":"uint256[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"changeCollectionOwner","inputs":[{"type":"address","name":"_nftContract","internalType":"address"},{"type":"address","name":"_newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"changeCreatorAndFeeContract","inputs":[{"type":"address","name":"_newCreatorContract","internalType":"address"},{"type":"address","name":"_newFeeContract","internalType":"address"},{"type":"address","name":"_beneficiary","internalType":"address payable"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"collections","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"createCollection","inputs":[{"type":"address","name":"_nftContract","internalType":"address"},{"type":"string","name":"_name","internalType":"string"},{"type":"string","name":"_symbol","internalType":"string"},{"type":"string","name":"_description","internalType":"string"},{"type":"string","name":"_collectionSlug","internalType":"string"},{"type":"bool","name":"_isFractional","internalType":"bool"},{"type":"uint16","name":"_creatorRoyaltyInPercentage","internalType":"uint16"},{"type":"address[]","name":"_creators","internalType":"address payable[]"},{"type":"uint16[]","name":"_percentages","internalType":"uint16[]"},{"type":"address","name":"_createdBy","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint16","name":"shareInPercentage","internalType":"uint16"},{"type":"address","name":"creator","internalType":"address payable"}],"name":"creatorFees","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"deleteCollection","inputs":[{"type":"address","name":"_nftContract","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"escrow","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IMarketPlaceFeeContract"}],"name":"feeContract","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[]","name":"collectionsList","internalType":"address[]"}],"name":"fetchCollectionsList","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple[]","name":"creators","internalType":"struct NFTMarket.Creator[]","components":[{"type":"uint16","name":"shareInPercentage","internalType":"uint16"},{"type":"address","name":"creator","internalType":"address payable"}]}],"name":"fetchCreators","inputs":[{"type":"address","name":"nftContract","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple[]","name":"","internalType":"struct NFTMarket.SaleLog[]","components":[{"type":"address","name":"seller","internalType":"address"},{"type":"address","name":"buyer","internalType":"address"},{"type":"uint256","name":"price","internalType":"uint256"},{"type":"uint256","name":"timestamp","internalType":"uint256"}]}],"name":"fetchPriceHistory","inputs":[{"type":"address","name":"_nftContract","internalType":"address"},{"type":"uint256","name":"_tokenId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple[]","name":"Asks","internalType":"struct NFTMarket.Ask[]","components":[{"type":"bool","name":"exists","internalType":"bool"},{"type":"address","name":"seller","internalType":"address"},{"type":"uint256","name":"price","internalType":"uint256"},{"type":"uint256","name":"quantity","internalType":"uint256"},{"type":"uint256","name":"timestamp","internalType":"uint256"}]},{"type":"tuple[]","name":"Bids","internalType":"struct NFTMarket.Bid[]","components":[{"type":"bool","name":"exists","internalType":"bool"},{"type":"address","name":"buyer","internalType":"address"},{"type":"uint256","name":"price","internalType":"uint256"},{"type":"uint256","name":"quantity","internalType":"uint256"},{"type":"uint256","name":"timestamp","internalType":"uint256"}]}],"name":"fetchTokenAsksAndBids","inputs":[{"type":"address","name":"nftContract","internalType":"address"},{"type":"uint256","name":"tokenId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"tokenIds","internalType":"uint256[]"}],"name":"fetchTokensInCollection","inputs":[{"type":"address","name":"nftContract","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[]","name":"userNFTAddresses","internalType":"address[]"},{"type":"uint256[]","name":"userNFTIds","internalType":"uint256[]"}],"name":"fetchUserNFTs","inputs":[{"type":"address","name":"_user","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"floorPrice","inputs":[{"type":"address","name":"nftContract","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"}],"name":"highestBid","inputs":[{"type":"address","name":"nftContract","internalType":"address"},{"type":"uint256","name":"tokenId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"approved","internalType":"bool"}],"name":"isApproved","inputs":[{"type":"address","name":"nftContract","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"lastTradedPrice","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"}],"name":"lowestAsk","inputs":[{"type":"address","name":"nftContract","internalType":"address"},{"type":"uint256","name":"tokenId","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":"view","outputs":[{"type":"address","name":"seller","internalType":"address"},{"type":"address","name":"buyer","internalType":"address"},{"type":"uint256","name":"price","internalType":"uint256"},{"type":"uint256","name":"timestamp","internalType":"uint256"}],"name":"priceHistory","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"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":"tokenIdsInCollection","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdraw","inputs":[{"type":"int256","name":"amount","internalType":"int256"}]}]
Deployed ByteCode
0x60806040526004361061023b5760003560e01c806373472f8c1161012e578063ae25a412116100ab578063d103c8041161006f578063d103c804146107fd578063e802123914610810578063f23a6e6114610848578063f2fde38b14610874578063fdbda0ec1461089457600080fd5b8063ae25a4121461071f578063ae9fa64c1461073f578063bc197c8114610781578063bd68b117146107ad578063c91e2c53146107db57600080fd5b80638fc80c01116100f25780638fc80c01146106465780639b03144114610674578063a0fca382146106bf578063a1d35c49146106df578063a6bb6cac146106ff57600080fd5b806373472f8c1461058e5780637e62eab8146105bb5780637ee6994c146105db578063817e8b71146105fb5780638da5cb5b1461062857600080fd5b806345d9039a116101bc5780635939b8c8116101805780635939b8c8146104f95780636390488114610519578063673448dd14610539578063715018a61461055957806372aa02401461056e57600080fd5b806345d9039a146103f857806346d02934146104255780635206af5b1461047757806357d3c7c3146104ac57806358f9aee2146104d957600080fd5b806326bf5a2c1161020357806326bf5a2c146103335780632aad99871461036a5780632d291cad1461039857806338af3eed146103c55780633ae6f942146103e557600080fd5b806301ffc9a71461024057806306e2971214610275578063145bbf8f146102ad578063150b7a02146102cf5780631a852d2d14610313575b600080fd5b34801561024c57600080fd5b5061026061025b366004614bb3565b6108b4565b60405190151581526020015b60405180910390f35b34801561028157600080fd5b50600254610295906001600160a01b031681565b6040516001600160a01b03909116815260200161026c565b3480156102b957600080fd5b506102cd6102c8366004614d3c565b6108eb565b005b3480156102db57600080fd5b506102fa6102ea366004614e34565b630a85bd0160e11b949350505050565b6040516001600160e01b0319909116815260200161026c565b34801561031f57600080fd5b506102cd61032e366004614ea0565b610beb565b34801561033f57600080fd5b5061035361034e366004614eeb565b610c54565b60405161026c9b9a99989796959493929190614f55565b34801561037657600080fd5b5061038a610385366004614eeb565b610edf565b60405190815260200161026c565b3480156103a457600080fd5b5061038a6103b3366004614eeb565b60056020526000908152604090205481565b3480156103d157600080fd5b50600e54610295906001600160a01b031681565b6102cd6103f3366004614ffe565b611133565b34801561040457600080fd5b5061041861041336600461509f565b611483565b60405161026c91906150cb565b34801561043157600080fd5b5061044561044036600461513b565b611531565b6040805195151586526001600160a01b039094166020860152928401919091526060830152608082015260a00161026c565b34801561048357600080fd5b5061049761049236600461509f565b611597565b6040805192835260208301919091520161026c565b3480156104b857600080fd5b5061038a6104c7366004614eeb565b60046020526000908152604090205481565b3480156104e557600080fd5b506102cd6104f4366004614ffe565b6117a1565b34801561050557600080fd5b5061038a61051436600461509f565b611ad9565b34801561052557600080fd5b506102cd610534366004615261565b611b0a565b34801561054557600080fd5b50610260610554366004614eeb565b611f76565b34801561056557600080fd5b506102cd611fe7565b34801561057a57600080fd5b5061049761058936600461509f565b61201d565b34801561059a57600080fd5b506105ae6105a9366004614eeb565b612218565b60405161026c919061539c565b3480156105c757600080fd5b506102cd6105d63660046153eb565b6122a4565b3480156105e757600080fd5b506102cd6105f6366004615404565b6123d9565b34801561060757600080fd5b5061061b610616366004614eeb565b61243d565b60405161026c9190615478565b34801561063457600080fd5b506001546001600160a01b0316610295565b34801561065257600080fd5b5061066661066136600461509f565b6124a9565b60405161026c9291906154c3565b34801561068057600080fd5b5061069461068f36600461513b565b612612565b604080516001600160a01b03958616815294909316602085015291830152606082015260800161026c565b3480156106cb57600080fd5b506104456106da36600461513b565b612673565b3480156106eb57600080fd5b506102cd6106fa366004614ffe565b61269b565b34801561070b57600080fd5b506102cd61071a366004614eeb565b61307c565b34801561072b57600080fd5b506102cd61073a366004614d3c565b61324d565b34801561074b57600080fd5b5061075f61075a36600461509f565b6135cb565b6040805161ffff90931683526001600160a01b0390911660208301520161026c565b34801561078d57600080fd5b506102fa61079c366004615552565b63bc197c8160e01b95945050505050565b3480156107b957600080fd5b506107cd6107c8366004614eeb565b61360e565b60405161026c929190615639565b3480156107e757600080fd5b506107f0613968565b60405161026c919061565e565b6102cd61080b366004614ffe565b6139ca565b34801561081c57600080fd5b5061038a61082b36600461509f565b600b60209081526000928352604080842090915290825290205481565b34801561085457600080fd5b506102fa610863366004615671565b63f23a6e6160e01b95945050505050565b34801561088057600080fd5b506102cd61088f366004614eeb565b61432d565b3480156108a057600080fd5b506102956108af3660046153eb565b6143c8565b60006001600160e01b03198216630271189760e51b14806108e557506301ffc9a760e01b6001600160e01b03198316145b92915050565b60005b8351811015610be557600084828151811061090b5761090b6156da565b602002602001015190506000848381518110610929576109296156da565b602002602001015190506000848481518110610947576109476156da565b6020908102919091018101516001600160a01b03851660009081526009835260408082208683529093529182208054919350908390811061098a5761098a6156da565b600091825260208083206004909202909101546001600160a01b0387811684526009835260408085208886529093529183208054610100909204929092169350849081106109da576109da6156da565b60009182526020808320600160049093020191909101546001600160a01b038816835260098252604080842088855290925290822080549193509085908110610a2557610a256156da565b9060005260206000209060040201600201549050336001600160a01b0316836001600160a01b031614610a9f5760405162461bcd60e51b815260206004820152601b60248201527f5245564552545f4e4f545f415f43524541544f525f4f465f41534b000000000060448201526064015b60405180910390fd5b6000610adb8787303386865b6040519080825280601f01601f191660200182016040528015610ad5576020820181803683370190505b506143f2565b905080610b1c5760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b6044820152606401610a96565b6001600160a01b03871660009081526009602090815260408083208984529091529020805486908110610b5157610b516156da565b60009182526020822060049091020180546001600160a81b03191681556001810182905560028101829055600301556040516001600160a01b038581169188918a16907f4e9b92658cc4158547a6653c2fe02ab320e55cd867b9fcc3a1f91cfbea4d9f4890610bc39088815260200190565b60405180910390a4505050505050508080610bdd90615706565b9150506108ee565b50505050565b6001546001600160a01b03163314610c155760405162461bcd60e51b8152600401610a9690615721565b600380546001600160a01b039485166001600160a01b0319918216179091556002805493851693821693909317909255600e8054919093169116179055565b6006602052600090815260409020805460018201805460ff808416946101008504909116936201000090046001600160a01b0316929091610c9490615756565b80601f0160208091040260200160405190810160405280929190818152602001828054610cc090615756565b8015610d0d5780601f10610ce257610100808354040283529160200191610d0d565b820191906000526020600020905b815481529060010190602001808311610cf057829003601f168201915b505050505090806002018054610d2290615756565b80601f0160208091040260200160405190810160405280929190818152602001828054610d4e90615756565b8015610d9b5780601f10610d7057610100808354040283529160200191610d9b565b820191906000526020600020905b815481529060010190602001808311610d7e57829003601f168201915b505050505090806003018054610db090615756565b80601f0160208091040260200160405190810160405280929190818152602001828054610ddc90615756565b8015610e295780601f10610dfe57610100808354040283529160200191610e29565b820191906000526020600020905b815481529060010190602001808311610e0c57829003601f168201915b505050505090806004018054610e3e90615756565b80601f0160208091040260200160405190810160405280929190818152602001828054610e6a90615756565b8015610eb75780601f10610e8c57610100808354040283529160200191610eb7565b820191906000526020600020905b815481529060010190602001808311610e9a57829003601f168201915b50505050600583015460068401546007850154600890950154939461ffff909216939092508b565b6001600160a01b0381166000908152600760209081526040808320805482518185028101850190935280835284938493929190830182828015610f4157602002820191906000526020600020905b815481526020019060010190808311610f2d575b50505050509050805160001415610f5c575060009392505050565b6001600160a01b0384166000908152600960205260408120825190919083908290610f8957610f896156da565b60200260200101518152602001908152602001600020600081548110610fb157610fb16156da565b906000526020600020906004020160010154915060005b815181101561112a576001600160a01b038516600090815260096020526040812083518290859085908110610fff57610fff6156da565b60200260200101518152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b828210156110a25760008481526020908190206040805160a08101825260048602909201805460ff81161515845261010090046001600160a01b03168385015260018082015492840192909252600281015460608401526003015460808301529083529092019101611035565b50505050905060005b815181101561111557848282815181106110c7576110c76156da565b60200260200101516040015110806110dd575084155b15611103578181815181106110f4576110f46156da565b60200260200101516040015194505b8061110d81615706565b9150506110ab565b5050808061112290615706565b915050610fc8565b50909392505050565b600260005414156111565760405162461bcd60e51b8152600401610a9690615791565b60026000558251845114801561116d575081518451145b801561117a575080518451145b6111965760405162461bcd60e51b8152600401610a96906157c8565b6000805b85518110156113ce5760008682815181106111b7576111b76156da565b6020026020010151905060008683815181106111d5576111d56156da565b6020026020010151905060008684815181106111f3576111f36156da565b602002602001015190506000868581518110611211576112116156da565b60200260200101519050611225848461453c565b611255576001600160a01b0384166000908152600760209081526040822080546001810182559083529120018390555b6001600160a01b038481166000818152600a602090815260408083208884528252808320815160a0810183526001808252338286018181528386018c8152606085018c8152426080870190815287548087018955978b529989902095516004909702909501805492516001600160a81b0319909316961515610100600160a81b0319169690961761010092909b1691909102999099178455975190830155516002820155925160039093019290925581518681529081018590528692917f7b8b1bb2c2858945a03c89fdb69e417239d7e78175bc50861cfb2fcb589ca34b910160405180910390a461134781836157f8565b6113519087615817565b9550336001600160a01b0316600080516020615a3883398151915260006040518060a00160405280600115158152602001336001600160a01b03168152602001868152602001858152602001428152506040516113af92919061582f565b60405180910390a25050505080806113c690615706565b91505061119a565b508034101561141b5760405162461bcd60e51b81526020600482015260196024820152782922ab22a92a2fa4a729aaa32324a1a4a2a72a2fa2aa2422a960391b6044820152606401610a96565b336000908152600460205260408120805483929061143a908490615817565b909155503390506108fc61144e8334615845565b6040518115909202916000818181858888f19350505050158015611476573d6000803e3d6000fd5b5050600160005550505050565b6001600160a01b0382166000908152600c602090815260408083208484528252808320805482518185028101850190935280835260609492939192909184015b82821015611525576000848152602090819020604080516080810182526004860290920180546001600160a01b0390811684526001808301549091168486015260028201549284019290925260030154606083015290835290920191016114c3565b50505050905092915050565b600a602052826000526040600020602052816000526040600020818154811061155957600080fd5b6000918252602090912060049091020180546001820154600283015460039093015460ff831696506101009092046001600160a01b03169450925085565b6001600160a01b03821660009081526009602090815260408083208484528252808320805482518185028101850190935280835284938493849384939192909190849084015b8282101561164a5760008481526020908190206040805160a08101825260048602909201805460ff81161515845261010090046001600160a01b031683850152600180820154928401929092526002810154606084015260030154608083015290835290920191016115dd565b505050509050805160001415611669576000809450945050505061179a565b8060008151811061167c5761167c6156da565b60200260200101516040015192508060008151811061169d5761169d6156da565b602002602001015160600151915060005b815181101561179257838282815181106116ca576116ca6156da565b60200260200101516040015110806116e0575083155b15611726578181815181106116f7576116f76156da565b6020026020010151604001519350818181518110611717576117176156da565b60200260200101516060015192505b83828281518110611739576117396156da565b602002602001015160400151148061174f575083155b1561178057818181518110611766576117666156da565b6020026020010151606001518361177d9190615817565b92505b8061178a81615706565b9150506116ae565b509193509150505b9250929050565b825184511480156117b3575081518451145b80156117c0575080518451145b6117dc5760405162461bcd60e51b8152600401610a96906157c8565b60005b8451811015611ad25760008582815181106117fc576117fc6156da565b60200260200101519050600085838151811061181a5761181a6156da565b602002602001015190506000858481518110611838576118386156da565b602002602001015190506000858581518110611856576118566156da565b60200260200101519050600082116118a05760405162461bcd60e51b815260206004820152600d60248201526c50524943455f4c545f5a45524f60981b6044820152606401610a96565b60006118ad8533866145c4565b116118ef5760405162461bcd60e51b81526020600482015260126024820152712727aa2fa7aba722a92fa7a32faa27a5a2a760711b6044820152606401610a96565b611911898681518110611904576119046156da565b6020026020010151611f76565b6119595760405162461bcd60e51b81526020600482015260196024820152782727aa2fa0a8282927ab22a22fa327a92faa2920a729a322a960391b6044820152606401610a96565b611963848461453c565b611993576001600160a01b0384166000908152600760209081526040822080546001810182559083529120018390555b6001600160a01b0384811660009081526009602090815260408083208784528252808320815160a0810183526001808252338286018181529483018a8152606084018a8152426080860190815286548086018855968a5297892094516004909602909401805496516001600160a81b0319909716951515610100600160a81b03191695909517610100969099169590950297909717835592519282019290925590516002820155905160039091015590611a539086908690308686610aab565b905080611a725760405162461bcd60e51b8152600401610a969061585c565b6040805184815260208101849052339186916001600160a01b038916917f8c40ed018f15133322f439beb851167a5acc361f1f1edaa5f33faea79a1eb341910160405180910390a450505050508080611aca90615706565b9150506117df565b5050505050565b60076020528160005260406000208181548110611af557600080fd5b90600052602060002001600091509150505481565b6003546001600160a01b0316331480611b2d57506001546001600160a01b031633145b611b685760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401610a96565b6001600160a01b038a1660009081526006602052604090206007015415611bc75760405162461bcd60e51b815260206004820152601360248201527222ac24a9aa24a723afa1a7a62622a1aa24a7a760691b6044820152606401610a96565b6000805b8351811015611c0d57838181518110611be657611be66156da565b602002602001015182611bf99190615889565b915080611c0581615706565b915050611bcb565b508061ffff166127101480611c24575061ffff8116155b611c705760405162461bcd60e51b815260206004820152601a60248201527f544f54414c5f50455243454e544147455f4e4f545f56414c49440000000000006044820152606401610a96565b611c78614a75565b6003546000906001600160a01b0316331415611c9d5750600160208201526000611d0e565b8c6001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015611cf7575060408051601f3d908101601f19168201909252611cf4918101906158af565b60015b611d0357506000611d06565b90505b600060208301525b8b82606001819052508a8260800181905250898260a00181905250888260c0018190525087826000019015159081151581525050808261010001818152505042826101200181815250508382604001906001600160a01b031690816001600160a01b031681525050868260e0019061ffff16908161ffff168152505081600660008f6001600160a01b03166001600160a01b0316815260200190815260200160002060008201518160000160006101000a81548160ff02191690831515021790555060208201518160000160016101000a81548160ff02191690831515021790555060408201518160000160026101000a8154816001600160a01b0302191690836001600160a01b031602179055506060820151816001019080519060200190611e39929190614ae0565b5060808201518051611e55916002840191602090910190614ae0565b5060a08201518051611e71916003840191602090910190614ae0565b5060c08201518051611e8d916004840191602090910190614ae0565b5060e082015160058201805461ffff191661ffff9092169190911790556101008201516006820155610120820151600782015561014090910151600890910155600d80546001810182556000919091527fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb50180546001600160a01b0319166001600160a01b038f16179055611f238d878761473c565b7f4ee07a34b5f5fb0472e88e587bb8677535739077b77a263caf2174d8da16bbb9600d805490508e8e8e42604051611f5f9594939291906158c8565b60405180910390a150505050505050505050505050565b60405163e985e9c560e01b81523360048201523060248201526000906001600160a01b0383169063e985e9c590604401602060405180830381865afa158015611fc3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108e59190615917565b6001546001600160a01b031633146120115760405162461bcd60e51b8152600401610a9690615721565b61201b6000614810565b565b6001600160a01b0382166000908152600a602090815260408083208484528252808320805482518185028101850190935280835284938493849384939192909190849084015b828210156120d05760008481526020908190206040805160a08101825260048602909201805460ff81161515845261010090046001600160a01b03168385015260018082015492840192909252600281015460608401526003015460808301529083529092019101612063565b5050505090508051600014156120ef576000809450945050505061179a565b80600081518110612102576121026156da565b602002602001015160400151925080600081518110612123576121236156da565b602002602001015160600151915060005b81518110156117925783828281518110612150576121506156da565b6020026020010151604001511180612166575083155b156121ac5781818151811061217d5761217d6156da565b602002602001015160400151935081818151811061219d5761219d6156da565b60200260200101516060015192505b838282815181106121bf576121bf6156da565b60200260200101516040015114806121d5575083155b15612206578181815181106121ec576121ec6156da565b602002602001015160600151836122039190615817565b92505b8061221081615706565b915050612134565b6001600160a01b0381166000908152600860209081526040808320805482518185028101850190935280835260609492939192909184015b82821015612299576000848152602090819020604080518082019091529084015461ffff811682526201000090046001600160a01b031681830152825260019092019101612250565b505050509050919050565b600260005414156122c75760405162461bcd60e51b8152600401610a9690615791565b600260009081556000198214156122ee5750336000908152600560205260409020546122f1565b50805b336000908152600560205260409020548111156123495760405162461bcd60e51b8152602060048201526016602482015275414d4f554e545f455843454544535f42414c414e434560501b6044820152606401610a96565b3360009081526005602052604081208054839290612368908490615845565b9091555050604051339082156108fc029083906000818181858888f1935050505015801561239a573d6000803e3d6000fd5b5060405181815233907f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b659060200160405180910390a250506001600055565b6001546001600160a01b031633146124035760405162461bcd60e51b8152600401610a9690615721565b6001600160a01b039182166000908152600660205260409020805492909116620100000262010000600160b01b0319909216919091179055565b6001600160a01b03811660009081526007602090815260409182902080548351818402810184019094528084526060939283018282801561249d57602002820191906000526020600020905b815481526020019060010190808311612489575b50505050509050919050565b6001600160a01b03821660008181526009602090815260408083208584528252808320938352600a825280832085845282528083208454825181850281018501909352808352606095869590949293928592919084015b8282101561256d5760008481526020908190206040805160a08101825260048602909201805460ff81161515845261010090046001600160a01b03168385015260018082015492840192909252600281015460608401526003015460808301529083529092019101612500565b50505050915080805480602002602001604051908101604052809291908181526020016000905b828210156126015760008481526020908190206040805160a08101825260048602909201805460ff81161515845261010090046001600160a01b03168385015260018082015492840192909252600281015460608401526003015460808301529083529092019101612594565b505050509050915091509250929050565b600c602052826000526040600020602052816000526040600020818154811061263a57600080fd5b600091825260209091206004909102018054600182015460028301546003909301546001600160a01b0392831696509116935090915084565b6009602052826000526040600020602052816000526040600020818154811061155957600080fd5b600260005414156126be5760405162461bcd60e51b8152600401610a9690615791565b6002600055825184511480156126d5575080518451145b80156126e2575081518451145b6126fe5760405162461bcd60e51b8152600401610a96906157c8565b60005b8451811015613070576000612749868381518110612721576127216156da565b60200260200101513387858151811061273c5761273c6156da565b60200260200101516145c4565b116127965760405162461bcd60e51b815260206004820152601c60248201527f5245564552545f4e4f545f4f574e45525f4f465f544f4b454e5f4944000000006044820152606401610a96565b60008582815181106127aa576127aa6156da565b6020026020010151905060008583815181106127c8576127c86156da565b6020026020010151905060008484815181106127e6576127e66156da565b602002602001015190506000868581518110612804576128046156da565b6020908102919091018101516001600160a01b0386166000908152600a8352604080822087835290935291822080549193509084908110612847576128476156da565b60009182526020808320600160049093020191909101546001600160a01b0388168352600a8252604080842088855290925290822080549193509085908110612892576128926156da565b906000526020600020906004020160000160019054906101000a90046001600160a01b031690506128ce8b8881518110611904576119046156da565b6129165760405162461bcd60e51b81526020600482015260196024820152782727aa2fa0a8282927ab22a22fa327a92faa2920a729a322a960391b6044820152606401610a96565b600061292487848689614862565b6002549091506001600160a01b03166374a129293361294387876157f8565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af115801561298e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129b291906158af565b600e546001600160a01b0316600090815260056020526040812080549091906129dc908490615817565b90915550506001600160a01b0387166000908152600a60209081526040808320898452909152902080543391600080516020615a38833981519152916001919089908110612a2c57612a2c6156da565b9060005260206000209060040201604051612a48929190615934565b60405180910390a26001600160a01b03871660009081526006602052604090205460ff16612bb15760005b6001600160a01b03881660009081526009602090815260408083208a8452909152902054811015612baf576001600160a01b03881660009081526009602090815260408083208a84529091528120805483908110612ad357612ad36156da565b60009182526020918290206040805160a0810182526004909302909101805460ff8116151584526001600160a01b0361010090910416938301849052600181015491830191909152600281015460608301526003015460808201529150331415612b9c576001600160a01b03891660009081526009602090815260408083208b84529091529020805483908110612b6c57612b6c6156da565b60009182526020822060049091020180546001600160a81b03191681556001810182905560028101829055600301555b5080612ba781615706565b915050612a73565b505b6001600160a01b0387166000908152600a602090815260408083208984529091528120805487908110612be657612be66156da565b600091825260208083206040805160a0810182526004909402909101805460ff8116151585526001600160a01b036101009091048116858501526001820154858401526002820154606086015260039091015460808501528c168452600a82528084208b855290915290912080549192509087908110612c6857612c686156da565b906000526020600020906004020160020154851015612ce4576001600160a01b0388166000908152600a602090815260408083208a84529091529020805486919088908110612cb957612cb96156da565b90600052602060002090600402016002016000828254612cd99190615845565b90915550612d499050565b6001600160a01b0388166000908152600a602090815260408083208a84529091529020805487908110612d1957612d196156da565b60009182526020822060049091020180546001600160a81b03191681556001810182905560028101829055600301555b612d5385856157f8565b6001600160a01b03891660009081526006602052604081206008018054909190612d7e908490615817565b90915550506001600160a01b0388166000908152600b602090815260408083208a84529091529020849055612db1614b64565b604080820186815242606084019081523384526001600160a01b0387811660208087019182528e83166000908152600c82528681208f82528252958620805460018181018355918852918720885160049093020180549285166001600160a01b031993841617815592519083018054919094169116179091559151600283015551600390910155612e4287876157f8565b6001600160a01b038616600090815260046020526040902054909150811115612ea15760405162461bcd60e51b81526020600482015260116024820152704c4f575f42555945525f42414c414e434560781b6044820152606401610a96565b6001600160a01b03851660009081526004602052604081208054839290612ec9908490615845565b9091555060009050612edf8b8b33898c86610aab565b905080612efe5760405162461bcd60e51b8152600401610a969061585c565b856001600160a01b0316600080516020615a38833981519152600086604051612f2892919061582f565b60405180910390a260408051888152602081018a905233918c916001600160a01b038f16917f08f6ba6b5c3c28e14bca6c0aae1205cd9ce920c14d34e2ae820b46ca2bde4e28910160405180910390a460025433906108fc9087906001600160a01b03166374a1292984612f9c8e8e6157f8565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af1158015612fe7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061300b91906158af565b6130158c8c6157f8565b61301f9190615845565b6130299190615845565b6040518115909202916000818181858888f19350505050158015613051573d6000803e3d6000fd5b505050505050505050505050808061306890615706565b915050612701565b50506001600055505050565b6001546001600160a01b031633146130a65760405162461bcd60e51b8152600401610a9690615721565b6130ae614a75565b6001600160a01b03808316600090815260066020908152604091829020845181548387015194870151909516620100000262010000600160b01b03199415156101000261ff00199215159290921661ffff1990961695909517179290921692909217815560608301518051849361312c926001850192910190614ae0565b5060808201518051613148916002840191602090910190614ae0565b5060a08201518051613164916003840191602090910190614ae0565b5060c08201518051613180916004840191602090910190614ae0565b5060e082015160058201805461ffff191661ffff909216919091179055610100820151600682015561012082015160078201556101409091015160089091015560005b600d5481101561324857826001600160a01b0316600d82815481106131ea576131ea6156da565b6000918252602090912001546001600160a01b0316141561323657600d8181548110613218576132186156da565b600091825260209091200180546001600160a01b0319169055505050565b8061324081615706565b9150506131c3565b505050565b600260005414156132705760405162461bcd60e51b8152600401610a9690615791565b600260009081555b83518110156135c0576000848281518110613295576132956156da565b6020026020010151905060008483815181106132b3576132b36156da565b6020026020010151905060008484815181106132d1576132d16156da565b6020908102919091018101516001600160a01b0385166000908152600a8352604080822086835290935291822080549193509083908110613314576133146156da565b600091825260208083206004909202909101546001600160a01b038781168452600a83526040808520888652909352918320805461010090920492909216935084908110613364576133646156da565b60009182526020808320600160049093020191909101546001600160a01b0388168352600a82526040808420888552909252908220805491935090859081106133af576133af6156da565b9060005260206000209060040201600201549050336001600160a01b0316836001600160a01b0316146134245760405162461bcd60e51b815260206004820152601b60248201527f5245564552545f4e4f545f415f43524541544f525f4f465f42494400000000006044820152606401610a96565b61342e81836157f8565b336000908152600460205260408120805490919061344d908490615845565b90915550506001600160a01b0386166000908152600a60209081526040808320888452909152902080543391600080516020615a3883398151915291600191908890811061349d5761349d6156da565b90600052602060002090600402016040516134b9929190615934565b60405180910390a26001600160a01b0386166000908152600a6020908152604080832088845290915290208054859081106134f6576134f66156da565b60009182526020822060049091020180546001600160a81b03191681556001810182905560028101829055600301556040516001600160a01b038481169187918916907fd13439b59bf64edb9f3794d39d9434e6738dad1412bcb7828071102db0f07a3c906135689087815260200190565b60405180910390a4336108fc61357e83856157f8565b6040518115909202916000818181858888f193505050501580156135a6573d6000803e3d6000fd5b5050505050505080806135b890615706565b915050613278565b505060016000555050565b600860205281600052604060002081815481106135e757600080fd5b60009182526020909120015461ffff811692506201000090046001600160a01b0316905082565b6060806000805b600d548110156139615760006001600160a01b0316600d828154811061363d5761363d6156da565b6000918252602090912001546001600160a01b0316141561365d5761394f565b6000600d8281548110613672576136726156da565b60009182526020822001546001600160a01b031691505b6001600160a01b03821660009081526007602052604090205481101561394c576001600160a01b03821660009081526006602052604090205460ff1615613808576001600160a01b0382166000818152600760205260408120805491929162fdd58e918b91869081106136fe576136fe6156da565b6000918252602090912001546040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015613753573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061377791906158af565b11156138035781868581518110613790576137906156da565b6001600160a01b0392831660209182029290920181019190915290831660009081526007909152604090208054829081106137cd576137cd6156da565b90600052602060002001548585815181106137ea576137ea6156da565b6020908102919091010152836137ff81615706565b9450505b61393a565b6001600160a01b03821660008181526007602052604090208054339291636352211e918590811061383b5761383b6156da565b90600052602060002001546040518263ffffffff1660e01b815260040161386491815260200190565b602060405180830381865afa158015613881573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138a59190615980565b6001600160a01b0316141561393a57818685815181106138c7576138c76156da565b6001600160a01b039283166020918202929092018101919091529083166000908152600790915260409020805482908110613904576139046156da565b9060005260206000200154858581518110613921576139216156da565b60209081029190910101528361393681615706565b9450505b8061394481615706565b915050613689565b50505b8061395981615706565b915050613615565b5050915091565b6060600d8054806020026020016040519081016040528092919081815260200182805480156139c057602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116139a2575b5050505050905090565b600260005414156139ed5760405162461bcd60e51b8152600401610a9690615791565b600260005582518451148015613a04575080518451145b8015613a11575081518451145b613a2d5760405162461bcd60e51b8152600401610a96906157c8565b6000805b85518110156142d2576000868281518110613a4e57613a4e6156da565b602002602001015190506000868381518110613a6c57613a6c6156da565b602002602001015190506000858481518110613a8a57613a8a6156da565b602002602001015190506000878581518110613aa857613aa86156da565b6020908102919091018101516001600160a01b038616600090815260098352604080822087835290935291822080549193509084908110613aeb57613aeb6156da565b600091825260208083206004909202909101546001600160a01b0388168352600982526040808420888552909252908220805460ff90921693509085908110613b3657613b366156da565b600091825260208083206004909202909101546001600160a01b0389811684526009835260408085208a8652909352918320805461010090920492909216935086908110613b8657613b866156da565b906000526020600020906004020160010154905082613be75760405162461bcd60e51b815260206004820152601960248201527f5245564552545f41534b5f444f45535f4e4f545f4558495354000000000000006044820152606401610a96565b6001600160a01b038216331415613c405760405162461bcd60e51b815260206004820152601a60248201527f5245564552545f43414e545f4143434550545f4f574e5f41534b0000000000006044820152606401610a96565b6001600160a01b03871660009081526009602090815260408083208984529091529020805486908110613c7557613c756156da565b906000526020600020906004020160020154841115613ccd5760405162461bcd60e51b81526020600482015260146024820152735155414e544954595f455843454544535f41534b60601b6044820152606401610a96565b613cd784826157f8565b613ce1908a615817565b98506000613cf18883878a614862565b6002549091506001600160a01b03166374a1292984613d1088866157f8565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af1158015613d5b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d7f91906158af565b600e546001600160a01b031660009081526005602052604081208054909190613da9908490615817565b90915550506001600160a01b0388811660009081526009602090815260408083208b845290915290208054918516917fadd0a9b0eaed1d49f1ee7dc64464ee681c63f4bf975dca98f176737ae590fdc3916001918a908110613e0d57613e0d6156da565b9060005260206000209060040201604051613e29929190615934565b60405180910390a26001600160a01b03881660009081526009602090815260408083208a84529091529020805487908110613e6657613e666156da565b906000526020600020906004020160020154851015613ee2576001600160a01b03881660009081526009602090815260408083208a84529091529020805486919088908110613eb757613eb76156da565b90600052602060002090600402016002016000828254613ed79190615845565b90915550613f479050565b6001600160a01b03881660009081526009602090815260408083208a84529091529020805487908110613f1757613f176156da565b60009182526020822060049091020180546001600160a81b03191681556001810182905560028101829055600301555b613f5185836157f8565b6001600160a01b03891660009081526006602052604081206008018054909190613f7c908490615817565b90915550506001600160a01b0388166000908152600b602090815260408083208a84529091529020829055613faf614b64565b82816040018181525050428160600181815250508381600001906001600160a01b031690816001600160a01b0316815250503381602001906001600160a01b031690816001600160a01b031681525050600c60008a6001600160a01b03166001600160a01b03168152602001908152602001600020600089815260200190815260200160002081908060018154018082558091505060019003906000526020600020906004020160009091909190915060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160010160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506040820151816002015560608201518160030155505060006140f38a8a30338b600067ffffffffffffffff811115610aab57610aab614bdd565b9050806141125760405162461bcd60e51b8152600401610a969061585c565b604080518581526020810189905233918b916001600160a01b038e16917f0dc226b1cce4a1d6749b9054e1ab856faeeed2ef2fd5f8b009a3d20d4032ba7a910160405180910390a46001600160a01b038a1660009081526009602090815260408083208c84529091528120805433927fadd0a9b0eaed1d49f1ee7dc64464ee681c63f4bf975dca98f176737ae590fdc39290918c9081106141b5576141b56156da565b90600052602060002090600402016040516141d1929190615934565b60405180910390a26002546001600160a01b03808716916108fc918691166374a12929896141ff8d8b6157f8565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af115801561424a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061426e91906158af565b6142788b896157f8565b6142829190615845565b61428c9190615845565b6040518115909202916000818181858888f193505050501580156142b4573d6000803e3d6000fd5b505050505050505050505080806142ca90615706565b915050613a31565b508034101561431f5760405162461bcd60e51b81526020600482015260196024820152782922ab22a92a2fa4a729aaa32324a1a4a2a72a2fa2aa2422a960391b6044820152606401610a96565b336108fc61144e8334615845565b6001546001600160a01b031633146143575760405162461bcd60e51b8152600401610a9690615721565b6001600160a01b0381166143bc5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610a96565b6143c581614810565b50565b600d81815481106143d857600080fd5b6000918252602090912001546001600160a01b0316905081565b604051635c46a7ef60e11b81526000906001600160a01b0388169063b88d4fde9061442790889088908b90889060040161599d565b600060405180830381600087803b15801561444157600080fd5b505af1925050508015614452575060015b61452e573d808015614480576040519150601f19603f3d011682016040523d82523d6000602084013e614485565b606091505b50604051637921219560e11b81526001600160a01b0389169063f242432a906144ba90899089908c908a908a906004016159d0565b600060405180830381600087803b1580156144d457600080fd5b505af19250505080156144e5575060015b614524573d808015614513576040519150601f19603f3d011682016040523d82523d6000602084013e614518565b606091505b50600092505050614532565b6001915050614532565b5060015b9695505050505050565b6000805b6001600160a01b0384166000908152600760205260409020548110156145ba576001600160a01b038416600090815260076020526040902080548491908390811061458d5761458d6156da565b906000526020600020015414156145a85760019150506108e5565b806145b281615706565b915050614540565b5060009392505050565b6040516331a9108f60e11b8152600481018290526000906001600160a01b03851690636352211e90602401602060405180830381865afa925050508015614628575060408051601f3d908101601f1916820190925261462591810190615980565b60015b61470b573d808015614656576040519150601f19603f3d011682016040523d82523d6000602084013e61465b565b606091505b50604051627eeac760e11b81526001600160a01b0385811660048301526024820185905286169062fdd58e90604401602060405180830381865afa9250505080156146c3575060408051601f3d908101601f191682019092526146c0918101906158af565b60015b614702573d8080156146f1576040519150601f19603f3d011682016040523d82523d6000602084013e6146f6565b606091505b50600092505050614735565b91506147359050565b836001600160a01b0316816001600160a01b0316141561472f576001915050614735565b60009150505b9392505050565b60005b8251811015610be557604080518082019091526000808252602082015283828151811061476e5761476e6156da565b6020908102919091018101516001600160a01b031690820152825183908390811061479b5761479b6156da565b60209081029190910181015161ffff90811683526001600160a01b0380881660009081526008845260408120805460018101825590825290849020855191018054959094015190911662010000026001600160b01b03199094169116179190911790558061480881615706565b91505061473f565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6001600160a01b038416600090815260066020526040812060050154819061ffff1615614a6c5760005b6001600160a01b038716600090815260086020526040902054811015614a6a5760006148b886886157f8565b6001600160a01b0389166000908152600860205260408120805492935090916127109190859081106148ec576148ec6156da565b60009182526020808320909101546001600160a01b038d168352600690915260409091206005015461ffff918216916127109161492a9116866157f8565b6149349190615a15565b61493e91906157f8565b6149489190615a15565b90508060056000600860008d6001600160a01b03166001600160a01b031681526020019081526020016000208681548110614985576149856156da565b60009182526020808320909101546001600160a01b0362010000909104168352820192909252604001812080549091906149c0908490615817565b909155506149d090508185615817565b6001600160a01b038a16600081815260086020526040902080549296509091859081106149ff576149ff6156da565b60009182526020918290200154604080518581529283018a9052620100009091046001600160a01b0316917fff2e45a3ef00a9f7ac5964f5c99b4076de5ac15411f355f6163e1f9bb5f2c9a9910160405180910390a350508080614a6290615706565b91505061488c565b505b95945050505050565b60405180610160016040528060001515815260200160001515815260200160006001600160a01b0316815260200160608152602001606081526020016060815260200160608152602001600061ffff1681526020016000815260200160008152602001600081525090565b828054614aec90615756565b90600052602060002090601f016020900481019282614b0e5760008555614b54565b82601f10614b2757805160ff1916838001178555614b54565b82800160010185558215614b54579182015b82811115614b54578251825591602001919060010190614b39565b50614b60929150614b9e565b5090565b604051806080016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081525090565b5b80821115614b605760008155600101614b9f565b600060208284031215614bc557600080fd5b81356001600160e01b03198116811461473557600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715614c1c57614c1c614bdd565b604052919050565b600067ffffffffffffffff821115614c3e57614c3e614bdd565b5060051b60200190565b6001600160a01b03811681146143c557600080fd5b8035614c6881614c48565b919050565b600082601f830112614c7e57600080fd5b81356020614c93614c8e83614c24565b614bf3565b82815260059290921b84018101918181019086841115614cb257600080fd5b8286015b84811015614cd6578035614cc981614c48565b8352918301918301614cb6565b509695505050505050565b600082601f830112614cf257600080fd5b81356020614d02614c8e83614c24565b82815260059290921b84018101918181019086841115614d2157600080fd5b8286015b84811015614cd65780358352918301918301614d25565b600080600060608486031215614d5157600080fd5b833567ffffffffffffffff80821115614d6957600080fd5b614d7587838801614c6d565b94506020860135915080821115614d8b57600080fd5b614d9787838801614ce1565b93506040860135915080821115614dad57600080fd5b50614dba86828701614ce1565b9150509250925092565b600082601f830112614dd557600080fd5b813567ffffffffffffffff811115614def57614def614bdd565b614e02601f8201601f1916602001614bf3565b818152846020838601011115614e1757600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215614e4a57600080fd5b8435614e5581614c48565b93506020850135614e6581614c48565b925060408501359150606085013567ffffffffffffffff811115614e8857600080fd5b614e9487828801614dc4565b91505092959194509250565b600080600060608486031215614eb557600080fd5b8335614ec081614c48565b92506020840135614ed081614c48565b91506040840135614ee081614c48565b809150509250925092565b600060208284031215614efd57600080fd5b813561473581614c48565b6000815180845260005b81811015614f2e57602081850181015186830182015201614f12565b81811115614f40576000602083870101525b50601f01601f19169290920160200192915050565b8b151581528a151560208201526001600160a01b038a16604082015261016060608201819052600090614f8a8382018c614f08565b90508281036080840152614f9e818b614f08565b905082810360a0840152614fb2818a614f08565b905082810360c0840152614fc68189614f08565b915050614fd960e083018761ffff169052565b8461010083015283610120830152826101408301529c9b505050505050505050505050565b6000806000806080858703121561501457600080fd5b843567ffffffffffffffff8082111561502c57600080fd5b61503888838901614c6d565b9550602087013591508082111561504e57600080fd5b61505a88838901614ce1565b9450604087013591508082111561507057600080fd5b61507c88838901614ce1565b9350606087013591508082111561509257600080fd5b50614e9487828801614ce1565b600080604083850312156150b257600080fd5b82356150bd81614c48565b946020939093013593505050565b602080825282518282018190526000919060409081850190868401855b8281101561512e57815180516001600160a01b039081168652878201511687860152858101518686015260609081015190850152608090930192908501906001016150e8565b5091979650505050505050565b60008060006060848603121561515057600080fd5b833561515b81614c48565b95602085013595506040909401359392505050565b80151581146143c557600080fd5b8035614c6881615170565b803561ffff81168114614c6857600080fd5b600082601f8301126151ac57600080fd5b813560206151bc614c8e83614c24565b82815260059290921b840181019181810190868411156151db57600080fd5b8286015b84811015614cd65780356151f281614c48565b83529183019183016151df565b600082601f83011261521057600080fd5b81356020615220614c8e83614c24565b82815260059290921b8401810191818101908684111561523f57600080fd5b8286015b84811015614cd65761525481615189565b8352918301918301615243565b6000806000806000806000806000806101408b8d03121561528157600080fd5b61528a8b614c5d565b995060208b013567ffffffffffffffff808211156152a757600080fd5b6152b38e838f01614dc4565b9a5060408d01359150808211156152c957600080fd5b6152d58e838f01614dc4565b995060608d01359150808211156152eb57600080fd5b6152f78e838f01614dc4565b985060808d013591508082111561530d57600080fd5b6153198e838f01614dc4565b975061532760a08e0161517e565b965061533560c08e01615189565b955060e08d013591508082111561534b57600080fd5b6153578e838f0161519b565b94506101008d013591508082111561536e57600080fd5b5061537b8d828e016151ff565b92505061538b6101208c01614c5d565b90509295989b9194979a5092959850565b602080825282518282018190526000919060409081850190868401855b8281101561512e578151805161ffff1685528601516001600160a01b03168685015292840192908501906001016153b9565b6000602082840312156153fd57600080fd5b5035919050565b6000806040838503121561541757600080fd5b823561542281614c48565b9150602083013561543281614c48565b809150509250929050565b600081518084526020808501945080840160005b8381101561546d57815187529582019590820190600101615451565b509495945050505050565b602081526000614735602083018461543d565b8051151582526020808201516001600160a01b0316908301526040808201519083015260608082015190830152608090810151910152565b604080825283519082018190526000906020906060840190828701845b82811015615506576154f384835161548b565b60a09390930192908401906001016154e0565b5050508381038285015284518082528583019183019060005b818110156155455761553283855161548b565b9284019260a0929092019160010161551f565b5090979650505050505050565b600080600080600060a0868803121561556a57600080fd5b853561557581614c48565b9450602086013561558581614c48565b9350604086013567ffffffffffffffff808211156155a257600080fd5b6155ae89838a01614ce1565b945060608801359150808211156155c457600080fd5b6155d089838a01614ce1565b935060808801359150808211156155e657600080fd5b506155f388828901614dc4565b9150509295509295909350565b600081518084526020808501945080840160005b8381101561546d5781516001600160a01b031687529582019590820190600101615614565b60408152600061564c6040830185615600565b8281036020840152614a6c818561543d565b6020815260006147356020830184615600565b600080600080600060a0868803121561568957600080fd5b853561569481614c48565b945060208601356156a481614c48565b93506040860135925060608601359150608086013567ffffffffffffffff8111156156ce57600080fd5b6155f388828901614dc4565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060001982141561571a5761571a6156f0565b5060010190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b600181811c9082168061576a57607f821691505b6020821081141561578b57634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b602080825260169082015275082a4a482b2be988a9c8ea890a6be9a92a69a82a886960531b604082015260600190565b6000816000190483118215151615615812576158126156f0565b500290565b6000821982111561582a5761582a6156f0565b500190565b821515815260c08101614735602083018461548b565b600082821015615857576158576156f0565b500390565b60208082526013908201527214915591549517d3919517d393d517d4d15395606a1b604082015260600190565b600061ffff8083168185168083038211156158a6576158a66156f0565b01949350505050565b6000602082840312156158c157600080fd5b5051919050565b8581526001600160a01b038516602082015260a0604082018190526000906158f290830186614f08565b82810360608401526159048186614f08565b9150508260808301529695505050505050565b60006020828403121561592957600080fd5b815161473581615170565b821515815260c081016147356020830184805460ff81161515835260081c6001600160a01b03166020830152600181015460408301526002810154606083015260030154608090910152565b60006020828403121561599257600080fd5b815161473581614c48565b6001600160a01b038581168252841660208201526040810183905260806060820181905260009061453290830184614f08565b6001600160a01b03868116825285166020820152604081018490526060810183905260a060808201819052600090615a0a90830184614f08565b979650505050505050565b600082615a3257634e487b7160e01b600052601260045260246000fd5b50049056feb9db10fa5b7108fd32f0288e3e0e2fb1c8c605a6c29b9f638dd89c94fbd2bfdca2646970667358221220bb72679728d70940a2787dfda48023c0937a5b8a10d6d1dbfc95b06ccd7d837764736f6c634300080a0033