{"action":"created","issue":{"url":"https://api.github.com/repos/ethereum/EIPs/issues/721","repository_url":"https://api.github.com/repos/ethereum/EIPs","labels_url":"https://api.github.com/repos/ethereum/EIPs/issues/721/labels{/name}","comments_url":"https://api.github.com/repos/ethereum/EIPs/issues/721/comments","events_url":"https://api.github.com/repos/ethereum/EIPs/issues/721/events","html_url":"https://github.com/ethereum/EIPs/issues/721","id":259900225,"node_id":"MDU6SXNzdWUyNTk5MDAyMjU=","number":721,"title":"ERC: Non-fungible Token Standard","user":{"login":"dete","id":1195159,"node_id":"MDQ6VXNlcjExOTUxNTk=","avatar_url":"https://avatars0.githubusercontent.com/u/1195159?v=4","gravatar_id":"","url":"https://api.github.com/users/dete","html_url":"https://github.com/dete","followers_url":"https://api.github.com/users/dete/followers","following_url":"https://api.github.com/users/dete/following{/other_user}","gists_url":"https://api.github.com/users/dete/gists{/gist_id}","starred_url":"https://api.github.com/users/dete/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dete/subscriptions","organizations_url":"https://api.github.com/users/dete/orgs","repos_url":"https://api.github.com/users/dete/repos","events_url":"https://api.github.com/users/dete/events{/privacy}","received_events_url":"https://api.github.com/users/dete/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":355,"created_at":"2017-09-22T18:31:36Z","updated_at":"2018-07-17T09:09:04Z","closed_at":null,"author_association":"NONE","body":"This proposal has been accepted and merged as a draft standard, please see the [officially tracked version](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md) for the current draft.\r\n\r\nPlease see PR #841 for the discussions leading up to this draft, and use this thread (#721) for further discussion. (Or, if you have a concrete proposal, consider opening a new PR with your proposed changes.)\r\n\r\n<details><summary>Original Draft (Sep 20, 2017)</summary>\r\n\r\n## Preamble\r\n\r\n    EIP: <to be assigned>\r\n    Title: Non-fungible Token Standard\r\n    Author: Dieter Shirley <dete@axiomzen.co>\r\n    Type: Standard\r\n    Category: ERC\r\n    Status: Draft\r\n    Created: 2017-09-20\r\n\r\n\r\n\r\n## Simple Summary\r\nA standard interface for non-fungible tokens.\r\n\r\n## Abstract\r\nThe following standard allows for the implementation of a standard API for non-fungible tokens (henceforth referred to as \"NFTs\") within smart contracts. This standard provides basic functionality to track and transfer ownership of NFTs.\r\n\r\n## Motivation\r\nA standard interface allows any NFTs on Ethereum to be handled by general-purpose applications. In particular, it will allow for NFTs to be tracked in standardized wallets and traded on exchanges.\r\n\r\n## Specification\r\n_I wanted to get the community's \"first impression\" before spending a bunch of time detailing out these end-points; expect this section to be significantly expanded after the first round of feedback. I've left out \"obvious\" return values for skimmability, and included a few notes where the functionality warrants special interest._\r\n - ERC-20 compatibility:\r\n    - `name()` _optional_\r\n    - `symbol()` _optional_\r\n    - `totalSupply()` - Number of NFTs tracked by this contract\r\n    - `balanceOf(address _owner)` - Number of NFTs owned by a particular address\r\n - Basic ownership:\r\n    - `tokensOfOwnerByIndex(address _owner, uint _index) constant returns (uint tokenId)` - There's really no good way to return a list of NFTs by owner, but it's valuable functionality. You should strenuously avoid calling this method \"on-chain\" (i.e. from a non-`constant` contract function).\r\n    - `ownerOf(uint _tokenId) constant returns (address owner)`\r\n    - `transfer(address _to, uint _tokenId)`\r\n    - `approve(address _to, uint _tokenId)` – SHOULD be cleared by any `transfer()` operation\r\n    - `transferFrom(address _from, address _to, unit _tokenId)` - the sender must have been previously authorized by `approve()`. (Note: Technically, the `_from` address here can be inferred by calling `ownerOf(_tokenId)`. I've left it in for symmetry with the corresponding ERC-20 method, and to forestall the (somewhat subtle) bug that could result from not clearing the `approve` authorization inside a successful `transfer` call.)\r\n - NFT metadata (optional):\r\n    - `tokenMetadata(uint _tokenId) returns (string infoUrl)` - recommended format is IPFS or HTTP [multiaddress](https://github.com/multiformats/multiaddr) with `name`, `image`, and `description` sub-paths. IPFS is the preferred mechanism (immutable and more durable).  Example: If `tokenMetadata()` returns `/ipfs/QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG`, the object description would be accessible via `ipfs cat /ipfs/QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG/description`.\r\n\r\n## Rationale\r\nThere are many proposed uses of Ethereum smart contracts that depend on tracking individual, non-fungible tokens (NFTs). Examples of existing or planned NFTs are LAND in [Decentraland](https://decentraland.org/), the eponymous punks in [CryptoPunks](https://www.larvalabs.com/cryptopunks), and in-game items using systems like [Dmarket](https://www.dmarket.io) or [EnjinCoin](https://enjincoin.io/). Future uses include tracking real-world non-fungible assets, like real-estate (as envisioned by companies like [Ubitquity](https://www.ubitquity.io) or [Propy](https://tokensale.propy.com/)).  It is critical in each of these cases that these items are not \"lumped together\" as numbers in a ledger, but instead each token must have its ownership individually and atomically tracked. Regardless of the nature of these items, the ecosystem will be stronger if we create a standardized interface that allows for cross-functional non-fungible token management and sales platforms.\r\n\r\nThe basis of this standard is that every NFT is identified by a unique, 256-bit unsigned integer within its tracking contract. The pair `(contract address, asset ID)` will then be globally unique within the Ethereum ecosystem.\r\n\r\nThis standard has followed the model of ERC-20 as much as possible to minimize the effort required for wallets (in particular) to track non-fungible tokens, while echoing a well-understood standard.\r\n\r\n## Backwards Compatibility\r\nThis standard follows the semantics of ERC-20 as closely as possible, but can't be entirely compatible with it due to the fundamental differences between fungible and non-fungible tokens.\r\n\r\nExample non-fungible implementations as of September, 2017:\r\n - [CryptoPunks](https://www.larvalabs.com/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 NFTs as \"punks\".\r\n - [Auctionhouse Asset Interface](https://github.com/dob/auctionhouse/blob/master/contracts/Asset.sol) - @dob needed a generic interface for his Auctionhouse dapp (currently ice-boxed). His \"Asset\" contract is very simple, but is missing ERC-20 compatiblity, approve() functionality, and metadata. This effort is referenced in the discussion for [EIP-173](https://github.com/ethereum/EIPs/issues/173).\r\n\r\n(It should be noted that \"limited edition, collectable tokens\" like [Curio Cards](https://mycuriocards.com/) and [Rare Pepe](https://rarepepewallet.com/) are _not_ non-fungible tokens. 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).)\r\n\r\n## Implementation\r\n_Reference implementation forthcoming..._\r\n\r\n## Copyright\r\nCopyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).\r\n</details>\r\n\r\n<details><summary>Second Draft (Nov 9, 2017)</summary>\r\n\r\n## Preamble\r\n\r\n    EIP: <to be assigned>\r\n    Title: Non-fungible Token Standard\r\n    Author: Dieter Shirley <dete@axiomzen.co>\r\n    Type: Standard\r\n    Category: ERC\r\n    Status: Draft\r\n    Created: 2017-09-20\r\n\r\n\r\n\r\n## Simple Summary\r\nA standard interface for non-fungible tokens.\r\n\r\n## Abstract\r\nThis standard allows for the implementation of a standard API for non-fungible tokens (henceforth referred to as \"NFTs\") within smart contracts. This standard provides basic functionality to track and transfer ownership of NFTs.\r\n\r\n## Motivation\r\nA standard interface allows any NFTs on Ethereum to be handled by general-purpose applications. In particular, it will allow for NFTs to be tracked in standardized wallets and traded on exchanges.\r\n\r\n## Specification\r\n\r\n### ERC-20 Compatibility\r\n\r\n#### name\r\n\r\n``` js\r\nfunction name() constant returns (string name)\r\n```\r\n\r\n_OPTIONAL - It is recommend that this method is implemented for enhanced usability with wallets and exchanges, but interfaces and other contracts MUST NOT depend on the existence of this method._\r\n\r\nReturns the name of the collection of NFTs managed by this contract. - e.g. `\"My Non-Fungibles\"`.\r\n\r\n#### symbol\r\n\r\n``` js\r\nfunction symbol() constant returns (string symbol)\r\n```\r\n\r\n_OPTIONAL - It is recommend that this method is implemented for enhanced usability with wallets and exchanges, but interfaces and other contracts MUST NOT depend on the existence of this method._\r\n\r\nReturns a short string symbol referencing the entire collection of NFTs managed in this contract. e.g. \"MNFT\". This symbol SHOULD be short (3-8 characters is recommended), with no whitespace characters or new-lines and SHOULD be limited to the uppercase latin alphabet (i.e. the 26 letters used in English).\r\n\r\n#### totalSupply\r\n\r\n``` js\r\nfunction totalSupply() constant returns (uint256 totalSupply)\r\n```\r\n\r\nReturns the total number of NFTs currently tracked by this contract.\r\n\r\n#### balanceOf\r\n\r\n``` js\r\nfunction balanceOf(address _owner) constant returns (uint256 balance)\r\n```\r\n\r\nReturns the number of NFTs assigned to address `_owner`.\r\n\r\n### Basic Ownership\r\n\r\n#### ownerOf\r\n\r\n``` js\r\nfunction ownerOf(uint256 _tokenId) constant returns (address owner)\r\n```\r\n\r\nReturns the address currently marked as the owner of `_tokenID`. This method MUST `throw` if `_tokenID` does not represent an NFT currently tracked by this contract. This method MUST NOT return 0 (NFTs assigned to the zero address are considered destroyed, and queries about them should `throw`). \r\n\r\n#### approve\r\n\r\n``` js\r\nfunction approve(address _to, uint256 _tokenId)\r\n```\r\n\r\nGrants approval for address `_to` to take possession of the NFT with ID `_tokenId`. This method MUST `throw` if `msg.sender != ownerOf(_tokenId)`, or if `_tokenID` does not represent an NFT currently tracked by this contract, or if `msg.sender == _to`.\r\n\r\nOnly one address can \"have approval\" at any given time; calling `approveTransfer` with a new address revokes approval for the previous address. Calling this method with 0 as the `_to` argument clears approval for any address.\r\n\r\nSuccessful completion of this method MUST emit an `Approval` event (defined below) unless the caller is attempting to clear approval when there is no pending approval. In particular, an Approval event MUST be fired if the `_to` address is zero and there is some outstanding approval. Additionally, an Approval event MUST be fired if `_to` is already the currently approved address and this call otherwise has no effect. (i.e. An `approve()` call that \"reaffirms\" an existing approval MUST fire an event.)\r\n\r\nAction | Prior State | _to address | New State | Event\r\n-- | -- | -- | -- | --\r\nClear unset approval | Clear | 0 | Clear | None\r\nSet new approval | Clear | X | Set to X | Approval(owner, X, tokenID)\r\nChange approval | Set to X | Y | Set to Y | Approval(owner, Y, tokenID)\r\nReaffirm approval | Set to X | X | Set to X | Approval(owner, X, tokenID)\r\nClear approval | Set to X | 0 | Clear | Approval(owner, 0, tokenID)\r\n\r\n\r\nNote: ANY change of ownership of an NFT – whether directly through the `transfer` and `transferFrom` methods defined in this interface, or through any other mechanism defined in the conforming contract – MUST clear any and all approvals for the transferred NFT. The implicit clearing of approval via ownership transfer MUST also fire the event `Approval(0, _tokenId)` if there was an outstanding approval. (i.e. All actions that transfer ownership must emit the same Approval event, if any, as would emitted by calling `approve(0, _tokenID)`.)\r\n\r\n#### takeOwnership\r\n\r\n``` js\r\nfunction takeOwnership(uint256 _tokenId)\r\n```\r\n\r\nAssigns the ownership of the NFT with ID `_tokenId` to `msg.sender` if and only if `msg.sender` currently has approval (via a previous call to `approveTransfer`). A successful transfer MUST fire the `Transfer` event (defined below).\r\n\r\nThis method MUST transfer ownership to `msg.sender` or `throw`, no other outcomes can be possible. Reasons for failure include (but are not limited to):\r\n - `msg.sender` does not have approval for `_tokenId`\r\n - `_tokenID` does not represent an NFT currently tracked by this contract\r\n - `msg.sender` already has ownership of `_tokenId`\r\n\r\nImportant: Please refer to the Note in the `approveTransfer` method description; a successful transfer MUST clear pending approval.\r\n\r\n#### transfer\r\n\r\n``` js\r\nfunction transfer(address _to, uint256 _tokenId)\r\n```\r\n\r\nAssigns the ownership of the NFT with ID `_tokenId` to `_to` if and only if `msg.sender == ownerOf(_tokenId)`. A successful transfer MUST fire the `Transfer` event (defined below).\r\n\r\nThis method MUST transfer ownership to `_to` or `throw`, no other outcomes can be possible. Reasons for failure include (but are not limited to):\r\n - `msg.sender` is not the owner of `_tokenId`\r\n - `_tokenID` does not represent an NFT currently tracked by this contract\r\n - `_to` is 0 (Conforming contracts MAY have other methods to destroy or burn NFTs, which are conceptually \"transfers to 0\" and will emit `Transfer` events reflecting this. However, `transfer(0, tokenID)` MUST be treated as an error.)\r\n\r\nA conforming contract MUST allow the current owner to \"transfer\" a token to themselves, as a way of affirming ownership in the event stream. (i.e. it is valid for `_to == ownerOf(_tokenID)`.) This \"no-op transfer\" MUST be considered a successful transfer, and therefore MUST fire a `Transfer` event (with the same address for `_from` and `_to`).\r\n\r\nImportant: Please refer to the Note in the `approveTransfer` method description; a successful transfer MUST clear pending approval. _This includes no-op transfers to the current owner!_\r\n\r\n#### tokenOfOwnerByIndex\r\n\r\n``` js\r\nfunction tokenOfOwnerByIndex(address _owner, uint256 _index) constant returns (uint tokenId)\r\n````\r\n\r\n_OPTIONAL - It is recommend that this method is implemented for enhanced usability with wallets and exchanges, but interfaces and other contracts MUST NOT depend on the existence of this method._\r\n\r\nReturns the _nth_ NFT assigned to the address `_owner`, with _n_ specified by the `_index` argument. This method MUST `throw` if `_index >= balanceOf(_owner)`.\r\n\r\nRecommended usage is as follows:\r\n\r\n``` js\r\nuint256 ownerBalance = nonFungibleContract.balanceOf(owner);\r\n\r\nuint256[] memory ownerTokens = new uint256[](ownerBalance);\r\n\r\nfor (uint256 i = 0; i < ownerBalance; i++) {\r\n    ownerTokens[i] = nonFungibleContract.tokenOfOwnerByIndex(owner, i);\r\n}\r\n```\r\n\r\nImplementations MUST NOT assume that NFTs are accessed in any particular order by their callers (In particular, don't assume this method is called in a monotonically ascending loop.), and MUST ensure that calls to `tokenOfOwnerByIndex` are fully [idempotent](https://en.wikipedia.org/wiki/Idempotence) unless and until some non-`constant` function is called on this contract.\r\n\r\nCallers of `tokenOfOwnerByIndex` MUST never assume that the order of NFTs is maintained outside of a single operation, or through the invocation (direct or indirect) of any non-`constant` contract method.\r\n\r\nNOTE: Current limitations in Solidity mean that there is no efficient way to return a complete list of an address's NFTs with a single function call. Callers should not assume this method is implemented efficiently (from a gas standpoint) and should _strenuously avoid_ calling this method \"on-chain\" (i.e. from any non-`constant` contract function, or from any `constant` contract function that is likely to be called on-chain).\r\n\r\n### NFT Metadata\r\n\r\n#### tokenMetadata\r\n\r\n``` js\r\nfunction tokenMetadata(uint256 _tokenId) constant returns (string infoUrl)\r\n```\r\n\r\n_OPTIONAL - It is recommend that this method is implemented for enhanced usability with wallets and exchanges, but interfaces and other contracts MUST NOT depend on the existence of this method._\r\n\r\nReturns a [multiaddress](https://github.com/multiformats/multiaddr) string referencing an external resource bundle that contains (optionally localized) metadata about the NFT associated with `_tokenId`. The string MUST be an IPFS or HTTP(S) base path (without a trailing slash) to which specific subpaths are obtained through concatenation. (IPFS is the preferred format due to better scalability, persistence, and immutability.)\r\n\r\nStandard sub-paths:\r\n - name (required) - The `name` sub-path MUST contain the UTF-8 encoded name of the specific NFT (i.e. distinct from the name of the collection, as returned by the contract's `name` method). A name SHOULD be 50 characters or less, and unique amongst all NFTs tracked by this contract. A name MAY contain white space characters, but MUST NOT include new-line or carriage-return characters. A name MAY include a numeric component to differentiate from similar NFTs in the same contract. For example: \"Happy Token #157\".\r\n - image (optional) - If the `image` sub-path exists, it MUST contain a PNG, JPEG, or SVG image with at least 300 pixels of detail in each dimension. The image aspect ratio SHOULD be between 16:9 (landscape mode) and 2:3 (portrait mode). The image SHOULD be structured with a \"safe zone\" such that cropping the image to a maximal, central square doesn't remove any critical information. (The easiest way to meet this requirement is simply to use a 1:1 image aspect ratio.)\r\n - description (optional) - If the `description` sub-path exists, it MUST contain a UTF-8 encoded textual description of the asset. This description MAY contain multiple lines and SHOULD use a single new-line character to delimit explicit line-breaks, and two new-line characters to delimit paragraphs. The description MAY include [CommonMark](http://commonmark.org)-compatible Markdown annotations for styling. The description SHOULD be 1500 characters or less.\r\n - other metadata (optional) - A contract MAY choose to include any number of additional subpaths, where they are deemed useful. There may be future formal and informal standards for additional metadata fields independent of this standard.\r\n \r\nEach metadata subpath (including subpaths not defined in this standard) MUST contain a sub-path `default` leading to a file containing the default (i.e. unlocalized) version of the data for that metadata element. For example, an NFT with the metadata path `/ipfs/QmZU8bKEG8fhcQwKoLHfjtJoKBzvUT5LFR3f8dEz86WdVe` MUST contain the NFT's name as a UTF-8 encoded string available at the full path `/ipfs/QmZU8bKEG8fhcQwKoLHfjtJoKBzvUT5LFR3f8dEz86WdVe/name/default`. Additionally, each metadata subpath MAY have one or more localizations at a subpath of an [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) language code (the same language codes used for HTML). For example, `/ipfs/QmZU8bKEG8fhcQwKoLHfjtJoKBzvUT5LFR3f8dEz86WdVe/name/en` would have the name in English, and `/ipfs/QmZU8bKEG8fhcQwKoLHfjtJoKBzvUT5LFR3f8dEz86WdVe/name/fr` would have the name in French (note that even localized values need to have a `default` entry). Consumers of NFT metadata SHOULD look for a localized value before falling back to the `default` value. Consumers MUST NOT assume that all metadata subpaths for a particular NFT are localized similarly. For example, it will be common for the `name` and `image` objects to not be localized even when the `description` is.\r\n\r\nYou can explore the metadata package referenced in this example [here](https://ipfs.io/ipfs/QmZU8bKEG8fhcQwKoLHfjtJoKBzvUT5LFR3f8dEz86WdVe).\r\n\r\n### Events\r\n\r\n#### Transfer\r\n\r\nThis event MUST trigger when NFT ownership is transferred via any mechanism.\r\n\r\nAdditionally, the creation of new NFTs MUST trigger a Transfer event for each newly created NFTs, with a `_from` address of 0 and a `_to` address matching the owner of the new NFT (possibly the smart contract itself). The deletion (or burn) of any NFT MUST trigger a Transfer event with a `_to` address of 0 and a `_from` address of the owner of the NFT (now former owner!).\r\n\r\nNOTE: A Transfer event with `_from == _to` is valid. See the `transfer()` documentation for details.\r\n\r\n``` js\r\nevent Transfer(address indexed _from, address indexed _to, uint256 _tokenId)\r\n```\r\n\r\n#### Approval\r\n\r\nThis event MUST trigger on any successful call to `approve(address _spender, uint256 _value)` (unless the caller is attempting to clear approval when there is no pending approval).\r\n\r\nSee the documentation for the `approve()` method above for further detail.\r\n\r\n\r\n``` js\r\nevent Approval(address indexed _owner, address indexed _approved, uint256 _tokenId)\r\n```\r\n\r\n\r\n## Rationale\r\n\r\n### Utility\r\n\r\nThere are many proposed uses of Ethereum smart contracts that depend on tracking individual, non-fungible tokens (NFTs). Examples of existing or planned NFTs are LAND in [Decentraland](https://decentraland.org/), the eponymous punks in [CryptoPunks](https://www.larvalabs.com/cryptopunks), and in-game items using systems like [Dmarket](https://www.dmarket.io) or [EnjinCoin](https://enjincoin.io/). Future uses include tracking real-world non-fungible assets, like real-estate (as envisioned by companies like [Ubitquity](https://www.ubitquity.io) or [Propy](https://tokensale.propy.com/)).  It is critical in each of these cases that these items are not \"lumped together\" as numbers in a ledger, but instead, each token must have its ownership individually and atomically tracked. Regardless of the nature of these items, the ecosystem will be stronger if we have a standardized interface that allows for cross-functional non-fungible token management and sales platforms.\r\n\r\n### NTF IDs\r\n\r\nThe basis of this standard is that every NFT is identified by a unique, 256-bit unsigned integer within its tracking contract. This ID number MUST NOT change for the life of the contract. The pair `(contract address, asset ID)` will then be a globally unique and fully-qualified identifier for a specific NFT within the Ethereum ecosystem. While some contracts may find it convenient to start with ID 0 and simply increment by one for each new NFT, callers MUST NOT assume that ID numbers have any specific pattern to them, and should treat the ID as a \"black box\".\r\n\r\n## Backwards Compatibility\r\nThis standard follows the semantics of ERC-20 as closely as possible, but can't be entirely compatible with it due to the fundamental differences between fungible and non-fungible tokens.\r\n\r\nExample non-fungible implementations as of September 2017:\r\n - [CryptoPunks](https://www.larvalabs.com/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 NFTs as \"punks\".\r\n - [Auctionhouse Asset Interface](https://github.com/dob/auctionhouse/blob/master/contracts/Asset.sol) - @dob needed a generic interface for his Auctionhouse dapp (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](https://github.com/ethereum/EIPs/issues/173).\r\n\r\n(It should be noted that \"limited edition, collectable tokens\" like [Curio Cards](https://mycuriocards.com/) and [Rare Pepe](https://rarepepewallet.com/) are _not_ non-fungible tokens. 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).)\r\n\r\n## Implementation\r\n_Reference implementation forthcoming..._\r\n\r\n## Copyright\r\nCopyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).\r\n\r\n</details>"},"comment":{"url":"https://api.github.com/repos/ethereum/EIPs/issues/comments/405514164","html_url":"https://github.com/ethereum/EIPs/issues/721#issuecomment-405514164","issue_url":"https://api.github.com/repos/ethereum/EIPs/issues/721","id":405514164,"node_id":"MDEyOklzc3VlQ29tbWVudDQwNTUxNDE2NA==","user":{"login":"James-Sangalli","id":16630514,"node_id":"MDQ6VXNlcjE2NjMwNTE0","avatar_url":"https://avatars0.githubusercontent.com/u/16630514?v=4","gravatar_id":"","url":"https://api.github.com/users/James-Sangalli","html_url":"https://github.com/James-Sangalli","followers_url":"https://api.github.com/users/James-Sangalli/followers","following_url":"https://api.github.com/users/James-Sangalli/following{/other_user}","gists_url":"https://api.github.com/users/James-Sangalli/gists{/gist_id}","starred_url":"https://api.github.com/users/James-Sangalli/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/James-Sangalli/subscriptions","organizations_url":"https://api.github.com/users/James-Sangalli/orgs","repos_url":"https://api.github.com/users/James-Sangalli/repos","events_url":"https://api.github.com/users/James-Sangalli/events{/privacy}","received_events_url":"https://api.github.com/users/James-Sangalli/received_events","type":"User","site_admin":false},"created_at":"2018-07-17T09:09:04Z","updated_at":"2018-07-17T09:09:04Z","author_association":"NONE","body":"@dete I cannot understand why bulk transfers are not default or why when querying for a balance you must provide the tokenId instead of the address and returning the array. I understand that you say people can create their own functions on top but it seems to be setting a very bad example and many others will follow suit with the mandatory implementation instead of getting it right from the foundation.\r\n\r\nCorrect me if I am wrong; but I am yet to see a valid reason why transferring one by one is more logical or simpler to implement? It just seems more painful and wasteful. If you want to transfer only one, then you simply put one element in the array, what's hard about that?  \r\n\r\nThe same reasoning is problematic for querying balance, in cryptokitties you must iterate over every kitty to get the balance of one address, instead of mapping an address to an array of kitties, what is the reasoning behind this?  "}}
{"actor":{"display_login":"James-Sangalli"}}