NEP-7: Non-Fungible Token Standard (NRC-7)

NEP7
TitleNon-Fungible Token Standard (NRC-7)
Author(s)Yong Liu
Discussions Tohttps://github.com/newtonproject/NEPs/issues/7
CategoryTechnical
TypeNRC
StatusDraft
Created2020-04-29

Simple Summary #

A standard interface for non-fungible tokens, also known as deeds.

Abstract #

The following standard allows for the implementation of a standard API for NFTs within smart contracts. This standard provides basic functionality to track and transfer NFTs.

We considered use cases of NFTs being owned and transacted by individuals as well as consignment to third party brokers/wallets/auctioneers (“operators”). NFTs can represent ownership over digital or physical assets. We considered a diverse universe of assets, and we know you will dream up many more.

Motivation #

A standard interface allows wallet/broker/auction applications to work with any NFT on Ethereum. We provide for simple smart contracts as well as contracts that track an arbitrarily large number of NFTs. Additional applications are discussed below.

This standard is inspired by the ERC-721 token standard.

Specification #

Meta Data #

ItemDescriptionBehaviors/Properties
nameA descriptive name for a collection of NFTs in this contractcan not be changed
symbolAn abbreviated name for NFTs in this contractcan not be changed
tokenURIA distinct Uniform Resource Identifier (URI) for a given asset
ownercontract deployer, mint NFTs

Interaction / Functions / Event #

FunctionDescriptionBehaviors/Properties
mintmint a new tokenpermission: owner
transferOwnershipTransfers ownership of the contract to a new account (newOwner)permission: owner
transferFromTransfer ownership of an NFTspermission: current owner, an authorized operator, or the approved address for this NFT
safeTransferFromTransfers the ownership of an NFT from one address to another addresspermission: current owner, an authorized operator, or the approved address for this NFT
approveChange or reaffirm the approved address for an NFTpermission: NFT owner
setApprovalForAllEnable or disable approval for a third party (“operator”) to manage all of msg.sender’s assets
Query
balanceOfCount all NFTs assigned to an owner
ownerOfFind the owner of an NFT
getApprovedGet the approved address for a single NFT
isApprovedForAllQuery if an address is an authorized operator for another address
Event
OwnershipTransferredownership of the contract to a new account
TransferThis emits when ownership of any NFT changes by any mechanism
ApprovalThis emits when the approved address for an NFT is changed or reaffirmed
ApprovalForAllThis emits when an operator is enabled or disabled for an owner

Test Cases #

TBD

Implementation #


interface INRC7 {
    /**
     * @dev Emitted when `tokenId` token is transfered 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 Emitted when ownership of the contract to a new account (`newOwner`).
     */
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @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`, `to` cannot be zero.
     * - `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`, `to` cannot be zero.
     * - `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`, `to` cannot be zero.
      * - `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 {INRC7Receiver-onNRC7Received}, which is called upon a safe transfer.
      *
      * Emits a {Transfer} event.
      */
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) external;
}

/**
 * @title NRC7 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from NRC7 asset contracts.
 */
interface INRC7Receiver {

  /**
     * @notice Handle the receipt of an NFT
     * @dev The NRC7 smart contract calls this function on the recipient
     * after a {INRC7-safeTransferFrom}. This function MUST return the function selector,
     * otherwise the caller will revert the transaction. The selector to be
     * returned can be obtained as `this.onNRC7Received.selector`. This
     * function MAY throw to revert and reject the transfer.
     * Note: the NRC7 contract address is always the message sender.
     * @param operator The address which called `safeTransferFrom` function
     * @param from The address which previously owned the token
     * @param tokenId The NFT identifier which is being transferred
     * @param data Additional data with no specified format
     * @return bytes4 `bytes4(keccak256("onNRC7Received(address,address,uint256,bytes)"))`
     */
    function onNRC7Received(address operator, address from, uint256 tokenId, bytes memory data) public external returns (bytes4);
}

References #

  1. ERC-721 Token Standard. https://eips.ethereum.org/EIPS/eip-721

Copyright and related rights waived via CC0.