Skip to content

Learn ERC-721

Background

There are many proposed uses of Ethereum smart contracts that depend on tracking distinguishable assets. Examples of existing or planned NFTs are LAND in Decentraland, the eponymous punks in CryptoPunks, and in-game items using systems like DMarket or EnjinCoin. Future uses include tracking real-world assets, like real-estate (as envisioned by companies like Ubitquity or Propy). It is critical in each of these cases that these items are not “lumped together” as numbers in a ledger, but instead each asset must have its ownership individually and atomically tracked. Regardless of the nature of these assets, the ecosystem will be stronger if we have a standardized interface that allows for cross-functional asset management and sales platforms.

Summary

A standard interface for non-fungible token which allows for the implementation of a standard API for NFTs within smart contracts. NFTs can represent ownership over digital or physical assets

This standard provides basic functionality to track and transfer NFTs.

This standard is inspired by the ERC-20 token standard and builds on two years of experience since EIP-20 was created.EIP-20 is insufficient for tracking NFTs because each asset is distinct (non-fungible) whereas each of a quantity of tokens is identical (fungible).

Specification

Specification is done through a interface based on the solidity language. Solidity is the programming language used for the ethereum blockchain.

NFT identifiers

Every NFT is identified by a unique uint256 ID inside the ERC-721 smart contract. This identifying number SHALL NOT change for the life of the contract. The pair (contract address, uint256 tokenId) will then be a globally unique and fully-qualified identifier for a specific asset on an Ethereum chain.

In ERC-721 every NFT is unique, the quantity is none or one.

Creating of NFTs (“minting”) and destruction NFTs (“burning”) is not included in the specification.

Privacy

Wallets/brokers/auctioneers identified in the motivation section have a strong need to identify which NFTs an owner owns.

It may be interesting to consider a use case where NFTs are not enumerable, such as a private registry of property ownership, or a partially-private registry. However, privacy cannot be attained because an attacker can simply (!) call ownerOf for every possible tokenId.

Scalability

The working group deployed a contract, XXXXERC721, to Testnet which instantiates and tracks 340282366920938463463374607431768211456 different deeds (2^128). That’s enough to assign every IPV6 address to an Ethereum account owner, or to track ownership of nanobots a few micron in size and in aggregate totalling half the size of Earth. You can query it from the blockchain.

This illustration makes clear: the ERC-721 standard scales.

Transfer mechanism

ERC-721 standardizes a safe transfer function safeTransferFrom. Transfers may be initiated by:

  • The owner of an NFT
  • The approved address of an NFT
  • An authorized operator of the current owner of an NFT

The actual contract implementation MAY also throw exceptions in other situations. This allows implementations to achieve interesting results:

  • Disallow transfers if the contract is paused — prior art, CryptoKitties deployed contract, line 611
  • Blacklist certain address from receiving NFTs — prior art, CryptoKitties deployed contract, lines 565, 566
  • Charge a fee to both parties of a transaction
  • Read only NFT registry — always throw from unsafeTransfer, transferFrom, approve and setApprovalForAll

Interface ERC721 - Core specification

Events from interface ERC721:

  • Transfer - This emits when ownership of any NFT changes by any mechanism. In addition, if from==0, event represent NFT creation, if to==0 even represent NFT destroyed
  • Approval - This emits when the approved address for an NFT is changed or reaffirmed.
  • ApprovalForAll - This emits when an operator is enabled or disabled for an owner. The operator can manage all NFTs of the owner.

Functions from interface ERC721:

  • balanceOf - The number of NFTs owned by _owner, possibly zero
  • ownerOf - Find the owner of an NFT. @return The address of the owner of the NFT
  • safeTransferFrom - Transfers the ownership of an NFT from one address to another address
  • transferFrom - Same as safeTransferFrom, but if to is not capable of receiving NFTs it will be permanently lost
  • approve - Change or reaffirm the approved address for an NFT. Throws unless msg.sender is the current NFT owner, or an authorized operator of the current owner.
  • setApprovalForAll - Enable or disable approval for a third party ("operator") to manage all of msg.sender's assets
  • getApproved - Get the approved address for a single NFT
  • isApprovedForAll - Query if an address is an authorized operator for another address
  • supportsInterface - From ERC165 - Standard Interface Detection

Interface ERC721TokenReceiver - Wallet dependency

Wallet/broker/uaction must implement the wallet interface ERC721 ´onERC721Received(address _operator, address _from, uint256 _tokenId, bytes _data´.The ERC721 smart contract calls this function on the recipient after a transfer. This function MAY throw to revert and reject the transfer. Return of other than the magic value MUST result in the transaction being reverted.

Interface ERC721Metadata - NFT metadata

This allows your smart contract to be interrogated for its name and for details about the assets which your NFTs represent.

  • function name - A descriptive name for a collection of NFTs in this contract
  • function symbol - An abbreviated name for NFTs in this contract
  • tokenURI - URI for a given asset. The URI may point to a JSON file that conforms to the "ERC721 Metadata JSON Schema"

ERC721 Metadata JSON Schema - NFT metadata

Defined through the following JSON Schema:

´´´ { "title": "Asset Metadata", "type": "object", "properties": { "name": { "type": "string", "description": "Identifies the asset to which this NFT represents" }, "description": { "type": "string", "description": "Describes the asset to which this NFT represents" }, "image": { "type": "string", "description": "A URI pointing to a resource with mime type image/* representing the asset to which this NFT represents. Consider making any images at a width between 320 and 1080 pixels and aspect ratio between 1.91:1 and 4:5 inclusive." } } } ´´´

Interface ERC721Enumerable - Full list of NFTs

Functions from interface ERC721Enumerable:

  • totalSupply - A count of valid NFTs tracked by this contract, where each one of them has an assigned and queryable owner not equal to the zero address
  • tokenByIndex - Returns the token identifier for the given index. This can then be used for example against ERC721Metadata.tokenURI
  • tokenOfOwnerByIndex - Enumerate NFTs assigned to an owner. Index less than balanceOf(_owner)

Open questions

  1. What is the approved address for an NFT?
  2. safeTransferFrom - Why does it do the following When transfer is complete, this function /// checks if _to is a smart contract (code size > 0). If so, it calls /// onERC721Received on _to and throws if the return value is not /// bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))
  3. setApprovalForAll - Is this what trading platforms such as OpenSea does when listing an NFT?
  4. Can ERC721 Metadata JSON Schema contain additional data for NFT traits
  5. Is an event such as approve put on chain?

Contract examples

Superrare Cryptokitties Meebits

Sources

https://eips.ethereum.org/EIPS/eip-721