// SPDX-License-Identifier: MITpragmasolidity ^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}.
*/interfaceIERC165{
/**
* @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.
*/functionsupportsInterface(bytes4 interfaceId) externalviewreturns (bool);
}
Contract Source Code
File 5 of 8: IERC721.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;/**
* @dev Required interface of an ERC721 compliant contract.
*/interfaceIERC721{
/** Events *//**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/eventTransfer(addressindexedfrom, addressindexed to, uint256indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/eventApproval(addressindexed owner, addressindexed approved, uint256indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/eventApprovalForAll(addressindexed owner, addressindexed operator, bool approved);
/** Views *//**
* @dev Returns the number of tokens in ``owner``'s account.
*/functionbalanceOf(address owner) externalviewreturns (uint256 balance);
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/functiongetApproved(uint256 tokenId) externalviewreturns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/functionisApprovedForAll(address owner, address operator) externalviewreturns (bool);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/functionownerOf(uint256 tokenId) externalviewreturns (address owner);
/** Mutators *//**
* @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.
*/functionapprove(address to, uint256 tokenId) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must 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.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId
) external;
/**
* @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.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId,
bytescalldata data
) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/functionsetApprovalForAll(address operator, bool approved) 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.
*/functiontransferFrom(addressfrom,
address to,
uint256 tokenId
) external;
}
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/interfaceIERC721Receiver{
/**
* @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`.
*/functiononERC721Received(address operator,
addressfrom,
uint256 tokenId,
bytescalldata data
) externalreturns (bytes4);
}
Contract Source Code
File 8 of 8: NFTCollectionV2.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;import"./AccessControl.sol";
import"./interfaces/IERC165.sol";
import"./interfaces/IERC721.sol";
import"./interfaces/IERC721Metadata.sol";
import"./interfaces/IERC721Receiver.sol";
abstractcontractNFTCollectionV2isAccessControl, IERC165, IERC721, IERC721Metadata{
/** @dev IERC721 Fields */mapping(address=>uint256) internal _balances;
mapping(address=>mapping(address=>bool)) internal _operatorApprovals;
mapping(uint256=>address) internal _owners;
mapping(uint256=>address) internal _tokenApprovals;
/** @dev IERC721Enumerable */uint256internal _totalSupply;
stringinternal _baseURI;
/** @dev IERC165 Views *//**
* @dev See {IERC165-supportsInterface}.
*/functionsupportsInterface(bytes4 interfaceId) externalpureoverridereturns (bool) {
return interfaceId ==type(IERC721).interfaceId|| interfaceId ==type(IERC721Metadata).interfaceId;
}
/** @dev IERC721 Views *//**
* @dev Returns the number of tokens in ``owner``'s account.
*/functionbalanceOf(address owner_) externalviewoverridereturns (uint256 balance) {
return _balances[owner_];
}
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/functiongetApproved(uint256 tokenId) externalviewoverridereturns (address operator) {
return _tokenApprovals[tokenId];
}
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/functionisApprovedForAll(address owner_, address operator) externalviewoverridereturns (bool) {
return _operatorApprovals[owner_][operator];
}
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/functionownerOf(uint256 tokenId) externalviewoverridereturns (address) {
return _owners[tokenId];
}
/** @dev IERC721 Mutators *//**
* @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.
*/functionapprove(address to, uint256 tokenId) externaloverride{
address owner_ = _owners[tokenId];
require(to != owner_, "caller may not approve themself");
require(msg.sender== owner_ || _operatorApprovals[owner_][msg.sender], "unauthorized");
_approve(to, tokenId);
}
/**
* @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.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId
) externaloverride{
_ensureApprovedOrOwner(msg.sender, tokenId);
_transfer(from, to, tokenId);
if (_isContract(to)) {
IERC721Receiver(to).onERC721Received(msg.sender, from, tokenId, "");
}
}
/**
* @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.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId,
bytescalldata data
) externaloverride{
_ensureApprovedOrOwner(msg.sender, tokenId);
_transfer(from, to, tokenId);
if (_isContract(to)) {
IERC721Receiver(to).onERC721Received(msg.sender, from, tokenId, data);
}
}
/**
* @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.
*/functionsetApprovalForAll(address operator, bool approved) externaloverride{
require(operator !=msg.sender, "caller may not approve themself");
_operatorApprovals[msg.sender][operator] = approved;
emit ApprovalForAll(msg.sender, operator, approved);
}
/**
* @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.
*/functiontransferFrom(addressfrom,
address to,
uint256 tokenId
) externaloverride{
_ensureApprovedOrOwner(msg.sender, tokenId);
_transfer(from, to, tokenId);
}
/** IERC721Metadata Views */functiontokenURI(uint256 tokenId) externalviewoverridereturns (stringmemory) {
returnstring(abi.encodePacked(_baseURI, _toString(tokenId), ".json"));
}
/** Useful Methods */functionchangeBaseURI(stringmemory newURI) externalonlyAdmin{
_baseURI = newURI;
}
functiontotalSupply() externalviewreturns (uint256) {
return _totalSupply;
}
/** Helpers *//**
* @dev Approve `to` to operate on `tokenId`
*
* Emits a {Approval} event.
*/function_approve(address to, uint256 tokenId) private{
_tokenApprovals[tokenId] = to;
emit Approval(_owners[tokenId], to, tokenId);
}
function_ensureApprovedOrOwner(address spender, uint256 tokenId) privateview{
address owner_ = _owners[tokenId];
require(
spender == owner_ || spender == _tokenApprovals[tokenId] || _operatorApprovals[owner_][spender],
"unauthorized"
);
}
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/function_toString(uint256 value) internalpurereturns (stringmemory) {
if (value ==0) {
return"0";
}
uint256 temp = value;
uint256 digits;
while (temp !=0) {
digits++;
temp /=10;
}
bytesmemory buffer =newbytes(digits);
while (value !=0) {
digits -=1;
buffer[digits] =bytes1(uint8(48+uint256(value %10)));
value /=10;
}
returnstring(buffer);
}
function_isContract(address account) internalviewreturns (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 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(addressfrom,
address to,
uint256 tokenId
) private{
require(_owners[tokenId] ==from, "transfer of token that is not own");
require(to !=address(0), "transfer to the zero address");
// Clear approvals from the previous owner
_approve(address(0), tokenId);
_balances[from] -=1;
_balances[to] +=1;
_owners[tokenId] = to;
emit Transfer(from, to, tokenId);
}
}