Skip to content

Commit 2bddd12

Browse files
authored
Update transfer naming and interface IDs
1 parent 89d0162 commit 2bddd12

File tree

1 file changed

+35
-43
lines changed

1 file changed

+35
-43
lines changed

EIPS/eip-721.md

Lines changed: 35 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ pragma solidity ^0.4.20;
4646
4747
/// @title ERC-721 Non-Fungible Token Standard
4848
/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
49-
/// Note: the ERC-165 identifier for this interface is 0xTODO_FILL_IN
50-
interface ERC721 /* is ERC165 */ {
49+
/// Note: the ERC-165 identifier for this interface is 0x6466353c
50+
interface ERC721 /* is ERC165 */ {
5151
/// @dev This emits when ownership of any NFT changes by any mechanism.
5252
/// This event emits when NFTs are created (`from` == 0) and destroyed
5353
/// (`to` == 0). Exception: during contract creation, any number of NFTs
@@ -79,38 +79,38 @@ interface ERC721 /* is ERC165 */ {
7979
/// @return The address of the owner of the NFT
8080
function ownerOf(uint256 _tokenId) external view returns (address);
8181
82-
/// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
83-
/// TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE
84-
/// THEY MAY BE PERMANENTLY LOST
85-
/// @dev Throws unless `msg.sender` is the current owner, an authorized
86-
/// operator, or the approved address for this NFT. Throws if `_from` is
87-
/// not the current owner. Throws if `_to` is the zero address. Throws if
88-
/// `_tokenId` is not a valid NFT.
89-
/// @param _from The current owner of the NFT
90-
/// @param _to The new owner
91-
/// @param _tokenId The NFT to transfer
92-
function unsafeTransfer(address _from, address _to, uint256 _tokenId) external payable;
93-
9482
/// @notice Transfers the ownership of an NFT from one address to another address
9583
/// @dev Throws unless `msg.sender` is the current owner, an authorized
9684
/// operator, or the approved address for this NFT. Throws if `_from` is
9785
/// not the current owner. Throws if `_to` is the zero address. Throws if
9886
/// `_tokenId` is not a valid NFT. When transfer is complete, this function
9987
/// checks if `_to` is a smart contract (code size > 0). If so, it calls
100-
/// `onNFTReceived` on `_to` and throws if the return value is not
101-
/// `bytes4(keccak256("onNFTReceived(address,uint256,bytes)"))`.
88+
/// `onERC721Received` on `_to` and throws if the return value is not
89+
/// `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`.
10290
/// @param _from The current owner of the NFT
10391
/// @param _to The new owner
10492
/// @param _tokenId The NFT to transfer
10593
/// @param data Additional data with no specified format, sent in call to `_to`
106-
function transferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable;
94+
function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable;
10795
10896
/// @notice Transfers the ownership of an NFT from one address to another address
10997
/// @dev This works identically to the other function with an extra data parameter,
11098
/// except this function just sets data to []
11199
/// @param _from The current owner of the NFT
112100
/// @param _to The new owner
113101
/// @param _tokenId The NFT to transfer
102+
function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;
103+
104+
/// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
105+
/// TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE
106+
/// THEY MAY BE PERMANENTLY LOST
107+
/// @dev Throws unless `msg.sender` is the current owner, an authorized
108+
/// operator, or the approved address for this NFT. Throws if `_from` is
109+
/// not the current owner. Throws if `_to` is the zero address. Throws if
110+
/// `_tokenId` is not a valid NFT.
111+
/// @param _from The current owner of the NFT
112+
/// @param _to The new owner
113+
/// @param _tokenId The NFT to transfer
114114
function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
115115
116116
/// @notice Set or reaffirm the approved address for an NFT
@@ -132,13 +132,13 @@ interface ERC721 /* is ERC165 */ {
132132
/// @dev Throws if `_tokenId` is not a valid NFT
133133
/// @param _tokenId The NFT to find the approved address for
134134
/// @return The approved address for this NFT, or the zero address if there is none
135-
function getApproved(uint256 _tokenId) returns (address);
135+
function getApproved(uint256 _tokenId) external returns (address);
136136
137137
/// @notice Query if an address is an authorized operator for another address
138138
/// @param _owner The address that owns the NFTs
139139
/// @param _operator The address that acts on behalf of the owner
140140
/// @return True if `_operator` is an approved operator for `_owner`, false otherwise
141-
function isApprovedForAll(address _owner, address _operator) returns (bool);
141+
function isApprovedForAll(address _owner, address _operator) external view returns (bool);
142142
}
143143
144144
interface ERC165 {
@@ -155,6 +155,7 @@ interface ERC165 {
155155
A wallet/broker/auction application MUST implement the **wallet interface** if it will accept safe transfers.
156156

157157
```solidity
158+
/// @dev Note: the ERC-165 identifier for this interface is 0xf0b9e5ba
158159
interface ERC721TokenReceiver {
159160
/// @notice Handle the receipt of an NFT
160161
/// @dev The ERC721 smart contract calls this function on the recipient
@@ -165,8 +166,9 @@ interface ERC721TokenReceiver {
165166
/// @param _from The sending address
166167
/// @param _tokenId The NFT identifier which is being transfered
167168
/// @param data Additional data with no specified format
168-
/// @return Always returns `keccak256("ERC721_ONNFTRECEIVED")`, unless throwing
169-
function onNFTReceived(address _from, uint256 _tokenId, bytes data) external returns(bytes4);
169+
/// @return `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`
170+
/// unless throwing
171+
function onERC721Received(address _from, uint256 _tokenId, bytes data) external returns(bytes4);
170172
}
171173
```
172174

@@ -175,7 +177,7 @@ The **metadata extension** is OPTIONAL for ERC-721 smart contracts (see "caveats
175177
```solidity
176178
/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension
177179
/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
178-
/// Note: the ERC-165 identifier for this interface is 0xTODO_ADD_THIS
180+
/// Note: the ERC-165 identifier for this interface is 0x5b5e139f
179181
interface ERC721Metadata /* is ERC721 */ {
180182
/// @notice A descriptive name for a collection of NFTs in this contract
181183
function name() external pure returns (string _name);
@@ -219,7 +221,7 @@ The **enumeration extension** is OPTIONAL for ERC-721 smart contracts (see "cave
219221
```solidity
220222
/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
221223
/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
222-
/// Note: the ERC-165 identifier for this interface is 0xTODO_ADD_THIS
224+
/// Note: the ERC-165 identifier for this interface is 0x780e9d63
223225
interface ERC721Enumerable /* is ERC721 */ {
224226
/// @notice Count NFTs tracked by this contract
225227
/// @return A count of valid NFTs tracked by this contract, where each one of
@@ -233,16 +235,6 @@ interface ERC721Enumerable /* is ERC721 */ {
233235
/// (sort order not specified)
234236
function tokenByIndex(uint256 _index) external view returns (uint256);
235237
236-
/// @notice Count of owners which own at least one NFT
237-
/// @return A count of the number of owners which own NFTs
238-
function countOfOwners() external view returns (uint256);
239-
240-
/// @notice Enumerate owners which own at least one NFT
241-
/// @dev Throws if `_index` >= `countOfOwners()`
242-
/// @param _index A counter less than `countOfOwners()`
243-
/// @return The address of the `_index`th owner (sort order not specified)
244-
function ownerByIndex(uint256 _index) external view returns (address);
245-
246238
/// @notice Enumerate NFTs assigned to an owner
247239
/// @dev Throws if `_index` >= `balanceOf(_owner)` or if
248240
/// `_owner` is the zero address, representing invalid NFTs.
@@ -283,27 +275,27 @@ The choice of `uint256` allows a wide variety of applications because UUIDs and
283275

284276
**Transfer mechanism**
285277

286-
ERC-721 standardizes a safe transfer function `transferFrom` (overloaded with and without a `bytes` parameter) and an unsafe function `unsafeTransfer`. Transfers may be initiated by:
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:
287279

288280
- The owner of an NFT
289281
- The approved address of an NFT
290282
- An authorized operator of the current owner of an NFT
291283

292284
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.
293285

294-
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:
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:
295287

296288
- **Disallow transfers if the contract is paused** — prior art, [Crypto Kitties](https://github.com/axiomzen/cryptokitties-bounty/blob/master/contracts/KittyOwnership.sol#L79)
297-
- **Blacklist certain address from receiving deeds** — prior art, [Crypto Kitties, (lines 565, 566)](https://etherscan.io/address/0x06012c8cf97bead5deae237070f9587f8e7a266d#code).
298-
- **Disallow unsafe transfers**`unsafeTransfer` throws unless `_to` equals `msg.sender` or `countOf(_to)` is non-zero (because such cases are safe)
299-
- **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 `transfer`, require `transfer` parameter `_to` to equal `msg.sender`, require `transfer` parameter `_to` to be the approved address for the deed
300-
- **Read only deed registry** — always throw from `unsafeTransfer`, `transferFrom`, `approve` and `setApprovalForAll`
289+
- **Blacklist certain address from receiving NFTs** — prior art, [Crypto Kitties, (lines 565, 566)](https://etherscan.io/address/0x06012c8cf97bead5deae237070f9587f8e7a266d#code).
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`
301293

302-
Failed transactions will throw, a best practice identified in [ERC-233](https://github.com/ethereum/EIPs/issues/223) , [ERC-677](https://github.com/ethereum/EIPs/issues/677), [ERC-827](https://github.com/ethereum/EIPs/issues/827) and [OpenZeppelin](https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/contracts/token/ERC20/SafeERC20.sol). [ERC-20](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md) defined an `allowance` feature, this caused a problem when called and then later modified to a different amount, as [disucssed on OpenZeppelin](https://github.com/OpenZeppelin/zeppelin-solidity/issues/438). In ERC-721, there is no allowance because every deed 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.
294+
Failed transactions will throw, a best practice identified in [ERC-233](https://github.com/ethereum/EIPs/issues/223) , [ERC-677](https://github.com/ethereum/EIPs/issues/677), [ERC-827](https://github.com/ethereum/EIPs/issues/827) and [OpenZeppelin](https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/contracts/token/ERC20/SafeERC20.sol). [ERC-20](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md) defined an `allowance` feature, this caused a problem when called and then later modified to a different amount, as [disucssed on OpenZeppelin](https://github.com/OpenZeppelin/zeppelin-solidity/issues/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.
303295

304296
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.
305297

306-
*Alternatives considered: only allow two-step ERC-20 style transaction, require that `transfer` never throw, require all functions to return a boolean indicating the success of the operation.*
298+
*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.*
307299

308300
**ERC-165 interface**
309301

@@ -358,15 +350,15 @@ We have been very inclusive in this process and invite anyone with questions or
358350

359351
We have adopted `balanceOf`, `totalSupply`, `name` and `symbol` semantics from the [ERC-20](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md) 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.
360352

361-
Example DAR implementations as of February 2018:
353+
Example NFT implementations as of February 2018:
362354

363355
- [CryptoKitties](https://www.cryptokitties.co/) — Compatible with an earlier version of this standard.
364356
- [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 assets as "punks".
365357
- [Auctionhouse Asset Interface](https://github.com/dob/auctionhouse/blob/master/contracts/Asset.sol)[@dob](https://github.com/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).
366358

367359
Note: "Limited edition, collectible tokens" like [Curio Cards](https://mycuriocards.com/) and [Rare Pepe](https://rarepepewallet.com/) 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).
368360

369-
The `onNFTReceived` function specifically works around old deployed contracts [which may inadvertently return 1 (`true`)](http://solidity.readthedocs.io/en/develop/bugs.html#DelegateCallReturnValue) in certain circumstances even if they don't implement a function. By returning, and checking for, a magic value we are able to distinguish actual affirmative responses versus these `true`s.
361+
The `onERC721Received` function specifically works around old deployed contracts [which may inadvertently return 1 (`true`)](http://solidity.readthedocs.io/en/develop/bugs.html#DelegateCallReturnValue) in certain circumstances even if they don't implement a function. By returning, and checking for, a magic value we are able to distinguish actual affirmative responses versus these `true`s.
370362

371363
## Test Cases
372364

0 commit comments

Comments
 (0)