/ EIPS / eip-721.md
eip-721.md
  1  ---
  2  eip: 721
  3  title: ERC-721 Non-Fungible Token Standard
  4  author: William Entriken <github.com@phor.net>, Dieter Shirley <dete@axiomzen.co>, Jacob Evans <jacob@dekz.net>, Nastassia Sachs <nastassia.sachs@protonmail.com>
  5  type: Standards Track
  6  category: ERC
  7  status: Final
  8  created: 2018-01-24
  9  requires: 165
 10  ---
 11  
 12  ## Simple Summary
 13  
 14  A standard interface for non-fungible tokens, also known as deeds.
 15  
 16  ## Abstract
 17  
 18  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.
 19  
 20  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:
 21  
 22  - Physical property — houses, unique artwork
 23  - Virtual collectables — unique pictures of kittens, collectable cards
 24  - "Negative value" assets — loans, burdens and other responsibilities
 25  
 26  In general, all houses are distinct and no two kittens are alike. NFTs are *distinguishable* and you must track the ownership of each one separately.
 27  
 28  ## Motivation
 29  
 30  A standard interface allows wallet/broker/auction applications to work with any NFT on Ethereum. We provide for simple ERC-721 smart contracts as well as contracts that track an *arbitrarily large* number of NFTs. Additional applications are discussed below.
 31  
 32  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).
 33  
 34  Differences between this standard and EIP-20 are examined below.
 35  
 36  ## Specification
 37  
 38  The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.
 39  
 40  **Every ERC-721 compliant contract must implement the `ERC721` and `ERC165` interfaces** (subject to "caveats" below):
 41  
 42  ```solidity
 43  pragma solidity ^0.4.20;
 44  
 45  /// @title ERC-721 Non-Fungible Token Standard
 46  /// @dev See https://eips.ethereum.org/EIPS/eip-721
 47  ///  Note: the ERC-165 identifier for this interface is 0x80ac58cd.
 48  interface ERC721 /* is ERC165 */ {
 49      /// @dev This emits when ownership of any NFT changes by any mechanism.
 50      ///  This event emits when NFTs are created (`from` == 0) and destroyed
 51      ///  (`to` == 0). Exception: during contract creation, any number of NFTs
 52      ///  may be created and assigned without emitting Transfer. At the time of
 53      ///  any transfer, the approved address for that NFT (if any) is reset to none.
 54      event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
 55  
 56      /// @dev This emits when the approved address for an NFT is changed or
 57      ///  reaffirmed. The zero address indicates there is no approved address.
 58      ///  When a Transfer event emits, this also indicates that the approved
 59      ///  address for that NFT (if any) is reset to none.
 60      event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);
 61  
 62      /// @dev This emits when an operator is enabled or disabled for an owner.
 63      ///  The operator can manage all NFTs of the owner.
 64      event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
 65  
 66      /// @notice Count all NFTs assigned to an owner
 67      /// @dev NFTs assigned to the zero address are considered invalid, and this
 68      ///  function throws for queries about the zero address.
 69      /// @param _owner An address for whom to query the balance
 70      /// @return The number of NFTs owned by `_owner`, possibly zero
 71      function balanceOf(address _owner) external view returns (uint256);
 72  
 73      /// @notice Find the owner of an NFT
 74      /// @dev NFTs assigned to zero address are considered invalid, and queries
 75      ///  about them do throw.
 76      /// @param _tokenId The identifier for an NFT
 77      /// @return The address of the owner of the NFT
 78      function ownerOf(uint256 _tokenId) external view returns (address);
 79  
 80      /// @notice Transfers the ownership of an NFT from one address to another address
 81      /// @dev Throws unless `msg.sender` is the current owner, an authorized
 82      ///  operator, or the approved address for this NFT. Throws if `_from` is
 83      ///  not the current owner. Throws if `_to` is the zero address. Throws if
 84      ///  `_tokenId` is not a valid NFT. When transfer is complete, this function
 85      ///  checks if `_to` is a smart contract (code size > 0). If so, it calls
 86      ///  `onERC721Received` on `_to` and throws if the return value is not
 87      ///  `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
 88      /// @param _from The current owner of the NFT
 89      /// @param _to The new owner
 90      /// @param _tokenId The NFT to transfer
 91      /// @param data Additional data with no specified format, sent in call to `_to`
 92      function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable;
 93  
 94      /// @notice Transfers the ownership of an NFT from one address to another address
 95      /// @dev This works identically to the other function with an extra data parameter,
 96      ///  except this function just sets data to "".
 97      /// @param _from The current owner of the NFT
 98      /// @param _to The new owner
 99      /// @param _tokenId The NFT to transfer
100      function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;
101  
102      /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
103      ///  TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE
104      ///  THEY MAY BE PERMANENTLY LOST
105      /// @dev Throws unless `msg.sender` is the current owner, an authorized
106      ///  operator, or the approved address for this NFT. Throws if `_from` is
107      ///  not the current owner. Throws if `_to` is the zero address. Throws if
108      ///  `_tokenId` is not a valid NFT.
109      /// @param _from The current owner of the NFT
110      /// @param _to The new owner
111      /// @param _tokenId The NFT to transfer
112      function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
113  
114      /// @notice Change or reaffirm the approved address for an NFT
115      /// @dev The zero address indicates there is no approved address.
116      ///  Throws unless `msg.sender` is the current NFT owner, or an authorized
117      ///  operator of the current owner.
118      /// @param _approved The new approved NFT controller
119      /// @param _tokenId The NFT to approve
120      function approve(address _approved, uint256 _tokenId) external payable;
121  
122      /// @notice Enable or disable approval for a third party ("operator") to manage
123      ///  all of `msg.sender`'s assets
124      /// @dev Emits the ApprovalForAll event. The contract MUST allow
125      ///  multiple operators per owner.
126      /// @param _operator Address to add to the set of authorized operators
127      /// @param _approved True if the operator is approved, false to revoke approval
128      function setApprovalForAll(address _operator, bool _approved) external;
129  
130      /// @notice Get the approved address for a single NFT
131      /// @dev Throws if `_tokenId` is not a valid NFT.
132      /// @param _tokenId The NFT to find the approved address for
133      /// @return The approved address for this NFT, or the zero address if there is none
134      function getApproved(uint256 _tokenId) external view returns (address);
135  
136      /// @notice Query if an address is an authorized operator for another address
137      /// @param _owner The address that owns the NFTs
138      /// @param _operator The address that acts on behalf of the owner
139      /// @return True if `_operator` is an approved operator for `_owner`, false otherwise
140      function isApprovedForAll(address _owner, address _operator) external view returns (bool);
141  }
142  
143  interface ERC165 {
144      /// @notice Query if a contract implements an interface
145      /// @param interfaceID The interface identifier, as specified in ERC-165
146      /// @dev Interface identification is specified in ERC-165. This function
147      ///  uses less than 30,000 gas.
148      /// @return `true` if the contract implements `interfaceID` and
149      ///  `interfaceID` is not 0xffffffff, `false` otherwise
150      function supportsInterface(bytes4 interfaceID) external view returns (bool);
151  }
152  ```
153  
154  A wallet/broker/auction application MUST implement the **wallet interface** if it will accept safe transfers.
155  
156  ```solidity
157  /// @dev Note: the ERC-165 identifier for this interface is 0x150b7a02.
158  interface ERC721TokenReceiver {
159      /// @notice Handle the receipt of an NFT
160      /// @dev The ERC721 smart contract calls this function on the recipient
161      ///  after a `transfer`. This function MAY throw to revert and reject the
162      ///  transfer. Return of other than the magic value MUST result in the
163      ///  transaction being reverted.
164      ///  Note: the contract address is always the message sender.
165      /// @param _operator The address which called `safeTransferFrom` function
166      /// @param _from The address which previously owned the token
167      /// @param _tokenId The NFT identifier which is being transferred
168      /// @param _data Additional data with no specified format
169      /// @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
170      ///  unless throwing
171      function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes _data) external returns(bytes4);
172  }
173  ```
174  
175  The **metadata extension** is OPTIONAL for ERC-721 smart contracts (see "caveats", below). This allows your smart contract to be interrogated for its name and for details about the assets which your NFTs represent.
176  
177  ```solidity
178  /// @title ERC-721 Non-Fungible Token Standard, optional metadata extension
179  /// @dev See https://eips.ethereum.org/EIPS/eip-721
180  ///  Note: the ERC-165 identifier for this interface is 0x5b5e139f.
181  interface ERC721Metadata /* is ERC721 */ {
182      /// @notice A descriptive name for a collection of NFTs in this contract
183      function name() external view returns (string _name);
184  
185      /// @notice An abbreviated name for NFTs in this contract
186      function symbol() external view returns (string _symbol);
187  
188      /// @notice A distinct Uniform Resource Identifier (URI) for a given asset.
189      /// @dev Throws if `_tokenId` is not a valid NFT. URIs are defined in RFC
190      ///  3986. The URI may point to a JSON file that conforms to the "ERC721
191      ///  Metadata JSON Schema".
192      function tokenURI(uint256 _tokenId) external view returns (string);
193  }
194  ```
195  
196  This is the "ERC721 Metadata JSON Schema" referenced above.
197  
198  ```json
199  {
200      "title": "Asset Metadata",
201      "type": "object",
202      "properties": {
203          "name": {
204              "type": "string",
205              "description": "Identifies the asset to which this NFT represents"
206          },
207          "description": {
208              "type": "string",
209              "description": "Describes the asset to which this NFT represents"
210          },
211          "image": {
212              "type": "string",
213              "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."
214          }
215      }
216  }
217  ```
218  
219  The **enumeration extension** is OPTIONAL for ERC-721 smart contracts (see "caveats", below). This allows your contract to publish its full list of NFTs and make them discoverable.
220  
221  ```solidity
222  /// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
223  /// @dev See https://eips.ethereum.org/EIPS/eip-721
224  ///  Note: the ERC-165 identifier for this interface is 0x780e9d63.
225  interface ERC721Enumerable /* is ERC721 */ {
226      /// @notice Count NFTs tracked by this contract
227      /// @return A count of valid NFTs tracked by this contract, where each one of
228      ///  them has an assigned and queryable owner not equal to the zero address
229      function totalSupply() external view returns (uint256);
230  
231      /// @notice Enumerate valid NFTs
232      /// @dev Throws if `_index` >= `totalSupply()`.
233      /// @param _index A counter less than `totalSupply()`
234      /// @return The token identifier for the `_index`th NFT,
235      ///  (sort order not specified)
236      function tokenByIndex(uint256 _index) external view returns (uint256);
237  
238      /// @notice Enumerate NFTs assigned to an owner
239      /// @dev Throws if `_index` >= `balanceOf(_owner)` or if
240      ///  `_owner` is the zero address, representing invalid NFTs.
241      /// @param _owner An address where we are interested in NFTs owned by them
242      /// @param _index A counter less than `balanceOf(_owner)`
243      /// @return The token identifier for the `_index`th NFT assigned to `_owner`,
244      ///   (sort order not specified)
245      function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256);
246  }
247  ```
248  
249  ### Caveats
250  
251  The 0.4.20 Solidity interface grammar is not expressive enough to document the ERC-721 standard. A contract which complies with ERC-721 MUST also abide by the following:
252  
253  - Solidity issue #3412: The above interfaces include explicit mutability guarantees for each function. Mutability guarantees are, in order weak to strong: `payable`, implicit nonpayable, `view`, and `pure`. Your implementation MUST meet the mutability guarantee in this interface and you MAY meet a stronger guarantee. For example, a `payable` function in this interface may be implemented as nonpayble (no state mutability specified) in your contract. We expect a later Solidity release will allow your stricter contract to inherit from this interface, but a workaround for version 0.4.20 is that you can edit this interface to add stricter mutability before inheriting from your contract.
254  - Solidity issue #3419: A contract that implements `ERC721Metadata` or `ERC721Enumerable` SHALL also implement `ERC721`. ERC-721 implements the requirements of interface ERC-165.
255  - Solidity issue #2330: If a function is shown in this specification as `external` then a contract will be compliant if it uses `public` visibility. As a workaround for version 0.4.20, you can edit this interface to switch to `public` before inheriting from your contract.
256  - Solidity issues #3494, #3544: Use of `this.*.selector` is marked as a warning by Solidity, a future version of Solidity will not mark this as an error.
257  
258  *If a newer version of Solidity allows the caveats to be expressed in code, then this EIP MAY be updated and the caveats removed, such will be equivalent to the original specification.*
259  
260  ## Rationale
261  
262  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.
263  
264  **"NFT" Word Choice**
265  
266  "NFT" was satisfactory to nearly everyone surveyed and is widely applicable to a broad universe of distinguishable digital assets. We recognize that "deed" is very descriptive for certain applications of this standard (notably, physical property).
267  
268  *Alternatives considered: distinguishable asset, title, token, asset, equity, ticket*
269  
270  **NFT Identifiers**
271  
272  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. While some ERC-721 smart contracts may find it convenient to start with ID 0 and simply increment by one for each new NFT, callers SHALL NOT assume that ID numbers have any specific pattern to them, and MUST treat the ID as a "black box". Also note that a NFTs MAY become invalid (be destroyed). Please see the enumerations functions for a supported enumeration interface.
273  
274  The choice of `uint256` allows a wide variety of applications because UUIDs and sha3 hashes are directly convertible to `uint256`.
275  
276  **Transfer Mechanism**
277  
278  ERC-721 standardizes a safe transfer function `safeTransferFrom` (overloaded with and without a `bytes` parameter) and an unsafe function `transferFrom`. Transfers may be initiated by:
279  
280  - The owner of an NFT
281  - The approved address of an NFT
282  - An authorized operator of the current owner of an NFT
283  
284  Additionally, an authorized operator may set the approved address for an NFT. This provides a powerful set of tools for wallet, broker and auction applications to quickly use a *large* number of NFTs.
285  
286  The transfer and accept functions' documentation only specify conditions when the transaction MUST throw. Your implementation MAY also throw in other situations. This allows implementations to achieve interesting results:
287  
288  - **Disallow transfers if the contract is paused** — prior art, CryptoKitties deployed contract, line 611
289  - **Blacklist certain address from receiving NFTs** — prior art, CryptoKitties deployed contract, lines 565, 566
290  - **Disallow unsafe transfers** — `transferFrom` throws unless `_to` equals `msg.sender` or `countOf(_to)` is non-zero or was non-zero previously (because such cases are safe)
291  - **Charge a fee to both parties of a transaction** — require payment when calling `approve` with a non-zero `_approved` if it was previously the zero address, refund payment if calling `approve` with the zero address if it was previously a non-zero address, require payment when calling any transfer function, require transfer parameter `_to` to equal `msg.sender`, require transfer parameter `_to` to be the approved address for the NFT
292  - **Read only NFT registry** — always throw from `unsafeTransfer`, `transferFrom`, `approve` and `setApprovalForAll`
293  
294  Failed transactions will throw, a best practice identified in ERC-223, ERC-677, ERC-827 and OpenZeppelin's implementation of SafeERC20.sol. ERC-20 defined an `allowance` feature, this caused a problem when called and then later modified to a different amount, as on OpenZeppelin issue \#438. In ERC-721, there is no allowance because every NFT is unique, the quantity is none or one. Therefore we receive the benefits of ERC-20's original design without problems that have been later discovered.
295  
296  Creating of NFTs ("minting") and destruction NFTs ("burning") is not included in the specification. Your contract may implement these by other means. Please see the `event` documentation for your responsibilities when creating or destroying NFTs.
297  
298  We questioned if the `operator` parameter on `onERC721Received` was necessary. In all cases we could imagine, if the operator was important then that operator could transfer the token to themself and then send it -- then they would be the `from` address. This seems contrived because we consider the operator to be a temporary owner of the token (and transferring to themself is redundant). When the operator sends the token, it is the operator acting on their own accord, NOT the operator acting on behalf of the token holder. This is why the operator and the previous token owner are both significant to the token recipient.
299  
300  *Alternatives considered: only allow two-step ERC-20 style transaction, require that transfer functions never throw, require all functions to return a boolean indicating the success of the operation.*
301  
302  **ERC-165 Interface**
303  
304  We chose Standard Interface Detection (ERC-165) to expose the interfaces that a ERC-721 smart contract supports.
305  
306  A future EIP may create a global registry of interfaces for contracts. We strongly support such an EIP and it would allow your ERC-721 implementation to implement `ERC721Enumerable`, `ERC721Metadata`, or other interfaces by delegating to a separate contract.
307  
308  **Gas and Complexity** (regarding the enumeration extension)
309  
310  This specification contemplates implementations that manage a few and *arbitrarily large* numbers of NFTs. If your application is able to grow then avoid using for/while loops in your code (see CryptoKitties bounty issue \#4). These indicate your contract may be unable to scale and gas costs will rise over time without bound.
311  
312  We have 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. And every function takes less gas than querying the ENS.
313  
314  This illustration makes clear: the ERC-721 standard scales.
315  
316  *Alternatives considered: remove the asset enumeration function if it requires a for-loop, return a Solidity array type from enumeration functions.*
317  
318  **Privacy**
319  
320  Wallets/brokers/auctioneers identified in the motivation section have a strong need to identify which NFTs an owner owns.
321  
322  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`.
323  
324  **Metadata Choices** (metadata extension)
325  
326  We have required `name` and `symbol` functions in the metadata extension. Every token EIP and draft we reviewed (ERC-20, ERC-223, ERC-677, ERC-777, ERC-827) included these functions.
327  
328  We remind implementation authors that the empty string is a valid response to `name` and `symbol` if you protest to the usage of this mechanism. We also remind everyone that any smart contract can use the same name and symbol as *your* contract. How a client may determine which ERC-721 smart contracts are well-known (canonical) is outside the scope of this standard.
329  
330  A mechanism is provided to associate NFTs with URIs. We expect that many implementations will take advantage of this to provide metadata for each NFT. The image size recommendation is taken from Instagram, they probably know much about image usability. The URI MAY be mutable (i.e. it changes from time to time). We considered an NFT representing ownership of a house, in this case metadata about the house (image, occupants, etc.) can naturally change.
331  
332  Metadata is returned as a string value. Currently this is only usable as calling from `web3`, not from other contracts. This is acceptable because we have not considered a use case where an on-blockchain application would query such information.
333  
334  *Alternatives considered: put all metadata for each asset on the blockchain (too expensive), use URL templates to query metadata parts (URL templates do not work with all URL schemes, especially P2P URLs), multiaddr network address (not mature enough)*
335  
336  **Community Consensus**
337  
338  A significant amount of discussion occurred on the original ERC-721 issue, additionally we held a first live meeting on Gitter that had good representation and well advertised (on Reddit, in the Gitter #ERC channel, and the original ERC-721 issue). Thank you to the participants:
339  
340  - [@ImAllInNow](https://github.com/imallinnow) Rob from DEC Gaming / Presenting Michigan Ethereum Meetup Feb 7
341  - [@Arachnid](https://github.com/arachnid) Nick Johnson
342  - [@jadhavajay](https://github.com/jadhavajay) Ajay Jadhav from AyanWorks
343  - [@superphly](https://github.com/superphly) Cody Marx Bailey - XRAM Capital / Sharing at hackathon Jan 20 / UN Future of Finance Hackathon.
344  - [@fulldecent](https://github.com/fulldecent) William Entriken
345  
346  A second event was held at ETHDenver 2018 to discuss distinguishable asset standards (notes to be published).
347  
348  We have been very inclusive in this process and invite anyone with questions or contributions into our discussion. However, this standard is written only to support the identified use cases which are listed herein.
349  
350  ## Backwards Compatibility
351  
352  We have adopted `balanceOf`, `totalSupply`, `name` and `symbol` semantics from the ERC-20 specification. An implementation may also include a function `decimals` that returns `uint8(0)` if its goal is to be more compatible with ERC-20 while supporting this standard. However, we find it contrived to require all ERC-721 implementations to support the `decimals` function.
353  
354  Example NFT implementations as of February 2018:
355  
356  - CryptoKitties -- Compatible with an earlier version of this standard.
357  - CryptoPunks -- Partially ERC-20 compatible, but not easily generalizable because it includes auction functionality directly in the contract and uses function names that explicitly refer to the assets as "punks".
358  - Auctionhouse Asset Interface -- The author needed a generic interface for the Auctionhouse ÐApp (currently ice-boxed). His "Asset" contract is very simple, but is missing ERC-20 compatibility, `approve()` functionality, and metadata. This effort is referenced in the discussion for EIP-173.
359  
360  Note: "Limited edition, collectible tokens" like Curio Cards and Rare Pepe are *not* distinguishable assets. They're actually a collection of individual fungible tokens, each of which is tracked by its own smart contract with its own total supply (which may be `1` in extreme cases).
361  
362  The `onERC721Received` function specifically works around old deployed contracts which may inadvertently return 1 (`true`) in certain circumstances even if they don't implement a function (see Solidity DelegateCallReturnValue bug). By returning and checking for a magic value, we are able to distinguish actual affirmative responses versus these vacuous `true`s.
363  
364  ## Test Cases
365  
366  0xcert ERC-721 Token includes test cases written using Truffle.
367  
368  ## Implementations
369  
370  0xcert ERC721 -- a reference implementation
371  
372  - MIT licensed, so you can freely use it for your projects
373  - Includes test cases
374  - Active bug bounty, you will be paid if you find errors
375  
376  Su Squares -- an advertising platform where you can rent space and place images
377  
378  - Complete the Su Squares Bug Bounty Program to seek problems with this standard or its implementation
379  - Implements the complete standard and all optional interfaces
380  
381  ERC721ExampleDeed -- an example implementation
382  
383  - Implements using the OpenZeppelin project format
384  
385  XXXXERC721, by William Entriken -- a scalable example implementation
386  
387  - Deployed on testnet with 1 billion assets and supporting all lookups with the metadata extension. This demonstrates that scaling is NOT a problem.
388  
389  ## References
390  
391  **Standards**
392  
393  1. ERC-20 Token Standard. https://eips.ethereum.org/EIPS/eip-20
394  1. ERC-165 Standard Interface Detection. https://eips.ethereum.org/EIPS/eip-165
395  1. ERC-173 Owned Standard. https://eips.ethereum.org/EIPS/eip-173
396  1. ERC-223 Token Standard. https://eips.ethereum.org/EIPS/eip-223
397  1. ERC-677 `transferAndCall` Token Standard. https://eips.ethereum.org/EIPS/eip-677
398  1. ERC-827 Token Standard. https://eips.ethereum.org/EIPS/eip-827
399  1. Ethereum Name Service (ENS). https://ens.domains
400  1. Instagram -- What's the Image Resolution? https://help.instagram.com/1631821640426723
401  1. JSON Schema. https://json-schema.org/
402  1. Multiaddr. https://github.com/multiformats/multiaddr
403  1. RFC 2119 Key words for use in RFCs to Indicate Requirement Levels. https://www.ietf.org/rfc/rfc2119.txt
404  
405  **Issues**
406  
407  1. The Original ERC-721 Issue. https://github.com/ethereum/eips/issues/721
408  1. Solidity Issue \#2330 -- Interface Functions are External. https://github.com/ethereum/solidity/issues/2330
409  1. Solidity Issue \#3412 -- Implement Interface: Allow Stricter Mutability. https://github.com/ethereum/solidity/issues/3412
410  1. Solidity Issue \#3419 -- Interfaces Can't Inherit. https://github.com/ethereum/solidity/issues/3419
411  1. Solidity Issue \#3494 -- Compiler Incorrectly Reasons About the `selector` Function. https://github.com/ethereum/solidity/issues/3494
412  1. Solidity Issue \#3544 -- Cannot Calculate Selector of Function Named `transfer`. https://github.com/ethereum/solidity/issues/3544
413  1. CryptoKitties Bounty Issue \#4 -- Listing all Kitties Owned by a User is `O(n^2)`. https://github.com/axiomzen/cryptokitties-bounty/issues/4
414  1. OpenZeppelin Issue \#438 -- Implementation of `approve` method violates ERC20 standard. https://github.com/OpenZeppelin/zeppelin-solidity/issues/438
415  1. Solidity DelegateCallReturnValue Bug. https://solidity.readthedocs.io/en/develop/bugs.html#DelegateCallReturnValue
416  
417  **Discussions**
418  
419  1. Reddit (announcement of first live discussion). https://www.reddit.com/r/ethereum/comments/7r2ena/friday_119_live_discussion_on_erc_nonfungible/
420  1. Gitter #EIPs (announcement of first live discussion). https://gitter.im/ethereum/EIPs?at=5a5f823fb48e8c3566f0a5e7
421  1. ERC-721 (announcement of first live discussion). https://github.com/ethereum/eips/issues/721#issuecomment-358369377
422  1. ETHDenver 2018. https://ethdenver.com
423  
424  **NFT Implementations and Other Projects**
425  
426  1. CryptoKitties. https://www.cryptokitties.co
427  1. 0xcert ERC-721 Token. https://github.com/0xcert/ethereum-erc721
428  1. Su Squares. https://tenthousandsu.com
429  1. Decentraland. https://decentraland.org
430  1. CryptoPunks. https://www.larvalabs.com/cryptopunks
431  1. DMarket. https://www.dmarket.io
432  1. Enjin Coin. https://enjincoin.io
433  1. Ubitquity. https://www.ubitquity.io
434  1. Propy. https://tokensale.propy.com
435  1. CryptoKitties Deployed Contract. https://etherscan.io/address/0x06012c8cf97bead5deae237070f9587f8e7a266d#code
436  1. Su Squares Bug Bounty Program. https://github.com/fulldecent/su-squares-bounty
437  1. XXXXERC721. https://github.com/fulldecent/erc721-example
438  1. ERC721ExampleDeed. https://github.com/nastassiasachs/ERC721ExampleDeed
439  1. Curio Cards. https://mycuriocards.com
440  1. Rare Pepe. https://rarepepewallet.com
441  1. Auctionhouse Asset Interface. https://github.com/dob/auctionhouse/blob/master/contracts/Asset.sol
442  1. OpenZeppelin SafeERC20.sol Implementation. https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/contracts/token/ERC20/SafeERC20.sol
443  
444  ## Copyright
445  
446  Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).