pragma solidity ^0.4.20;
/// @title ERC-721 Non-Fungible Token Standard
/// @dev See https://eips.ethereum.org/EIPS/eip-721
/// Note: the ERC-165 identifier for this interface is 0x80ac58cd.
interface ERC721 /* is ERC165 */ {
/// @dev This emits when ownership of any NFT changes by any mechanism.
/// This event emits when NFTs are created (`from` == 0) and destroyed
/// (`to` == 0). Exception: during contract creation, any number of NFTs
/// may be created and assigned without emitting Transfer. At the time of
/// any transfer, the approved address for that NFT (if any) is reset to none.
event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
/// @dev This emits when the approved address for an NFT is changed or
/// reaffirmed. The zero address indicates there is no approved address.
/// When a Transfer event emits, this also indicates that the approved
/// address for that NFT (if any) is reset to none.
event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);
/// @dev This emits when an operator is enabled or disabled for an owner.
/// The operator can manage all NFTs of the owner.
event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
/// @notice Count all NFTs assigned to an owner
/// @dev NFTs assigned to the zero address are considered invalid, and this
/// function throws for queries about the zero address.
/// @param _owner An address for whom to query the balance
/// @return The number of NFTs owned by `_owner`, possibly zero
function balanceOf(address _owner) external view returns (uint256);
/// @notice Find the owner of an NFT
/// @dev NFTs assigned to zero address are considered invalid, and queries
/// about them do throw.
/// @param _tokenId The identifier for an NFT
/// @return The address of the owner of the NFT
function ownerOf(uint256 _tokenId) external view returns (address);
/// @notice Transfers the ownership of an NFT from one address to another address
/// @dev Throws unless `msg.sender` is the current owner, an authorized
/// operator, or the approved address for this NFT. Throws if `_from` is
/// not the current owner. Throws if `_to` is the zero address. Throws if
/// `_tokenId` is not a valid NFT. 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)"))`.
/// @param _from The current owner of the NFT
/// @param _to The new owner
/// @param _tokenId The NFT to transfer
/// @param data Additional data with no specified format, sent in call to `_to`
function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable;
/// @notice Transfers the ownership of an NFT from one address to another address
/// @dev This works identically to the other function with an extra data parameter,
/// except this function just sets data to "".
/// @param _from The current owner of the NFT
/// @param _to The new owner
/// @param _tokenId The NFT to transfer
function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;
/// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
/// TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE
/// THEY MAY BE PERMANENTLY LOST
/// @dev Throws unless `msg.sender` is the current owner, an authorized
/// operator, or the approved address for this NFT. Throws if `_from` is
/// not the current owner. Throws if `_to` is the zero address. Throws if
/// `_tokenId` is not a valid NFT.
/// @param _from The current owner of the NFT
/// @param _to The new owner
/// @param _tokenId The NFT to transfer
function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
/// @notice Change or reaffirm the approved address for an NFT
/// @dev The zero address indicates there is no approved address.
/// Throws unless `msg.sender` is the current NFT owner, or an authorized
/// operator of the current owner.
/// @param _approved The new approved NFT controller
/// @param _tokenId The NFT to approve
function approve(address _approved, uint256 _tokenId) external payable;
/// @notice Enable or disable approval for a third party ("operator") to manage
/// all of `msg.sender`'s assets
/// @dev Emits the ApprovalForAll event. The contract MUST allow
/// multiple operators per owner.
/// @param _operator Address to add to the set of authorized operators
/// @param _approved True if the operator is approved, false to revoke approval
function setApprovalForAll(address _operator, bool _approved) external;
/// @notice Get the approved address for a single NFT
/// @dev Throws if `_tokenId` is not a valid NFT.
/// @param _tokenId The NFT to find the approved address for
/// @return The approved address for this NFT, or the zero address if there is none
function getApproved(uint256 _tokenId) external view returns (address);
/// @notice Query if an address is an authorized operator for another address
/// @param _owner The address that owns the NFTs
/// @param _operator The address that acts on behalf of the owner
/// @return True if `_operator` is an approved operator for `_owner`, false otherwise
function isApprovedForAll(address _owner, address _operator) external view returns (bool);
}
interface ERC165 {
/// @notice Query if a contract implements an interface
/// @param interfaceID The interface identifier, as specified in ERC-165
/// @dev Interface identification is specified in ERC-165. This function
/// uses less than 30,000 gas.
/// @return `true` if the contract implements `interfaceID` and
/// `interfaceID` is not 0xffffffff, `false` otherwise
function supportsInterface(bytes4 interfaceID) external view returns (bool);
}
```
Abstract
스마트 컨트랙트 내에서 NFT의 표준 API 인터페이스를 규정. 표준 API는 NFT를 교환하고 기록하기 위한 기본적인 기능을 제공한다.
NFT는 다음과 같은 다양한 디지털 또는 물리 자산에 대한 소유권을 나타낼 수 있다.
- 물리 자산 - 집, 예술 작품 등
- 수집품 - 유일성이 보장되는 수집용 카드 등
- 대출과 같은 마이너스 자산 등
NFT는 구별 가능한 디지털 토큰으로서 각 자산에 대해 개별적으로 소유권을 추적할 수 있도록 한다.
Specification
- ERC-721를 따르는 컨트랙트를 만들기 위해서는
ERC721
,ERC165
인터페이스를 반드시 구현해야한다. - 어플리케이션은 지갑 인터페이스를 구현해야한다.
/// @dev Note: the ERC-165 identifier for this interface is 0x150b7a02. interface ERC721TokenReceiver { /// @notice Handle the receipt of an NFT /// @dev 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. /// Note: the 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(keccak256("onERC721Received(address,address,uint256,bytes)"))` /// unless throwing function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes _data) external returns(bytes4); }
- (Optional) 토큰 이름과 상세 정보를 외부에 제공하도록 메타데이터 인터페이스를 구현할 수 있다.
/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension /// @dev See https://eips.ethereum.org/EIPS/eip-721 /// Note: the ERC-165 identifier for this interface is 0x5b5e139f. interface ERC721Metadata /* is ERC721 */ { /// @notice A descriptive name for a collection of NFTs in this contract function name() external view returns (string _name); /// @notice An abbreviated name for NFTs in this contract function symbol() external view returns (string _symbol); /// @notice A distinct Uniform Resource Identifier (URI) for a given asset. /// @dev Throws if `_tokenId` is not a valid NFT. URIs are defined in RFC /// 3986. The URI may point to a JSON file that conforms to the "ERC721 /// Metadata JSON Schema". function tokenURI(uint256 _tokenId) external view returns (string); }
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters// "ERC721 Metadata JSON Schema" referenced above. { "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." } } } - (Optional) enumeration extension : 모든 NFT를 검색할 수 있도록 함.
/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension /// @dev See https://eips.ethereum.org/EIPS/eip-721 /// Note: the ERC-165 identifier for this interface is 0x780e9d63. interface ERC721Enumerable /* is ERC721 */ { /// @notice Count NFTs tracked by this contract /// @return 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 function totalSupply() external view returns (uint256); /// @notice Enumerate valid NFTs /// @dev Throws if `_index` >= `totalSupply()`. /// @param _index A counter less than `totalSupply()` /// @return The token identifier for the `_index`th NFT, /// (sort order not specified) function tokenByIndex(uint256 _index) external view returns (uint256); /// @notice Enumerate NFTs assigned to an owner /// @dev Throws if `_index` >= `balanceOf(_owner)` or if /// `_owner` is the zero address, representing invalid NFTs. /// @param _owner An address where we are interested in NFTs owned by them /// @param _index A counter less than `balanceOf(_owner)` /// @return The token identifier for the `_index`th NFT assigned to `_owner`, /// (sort order not specified) function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256); }
Rationale
- NFT Identifiers
: NFT는uint256
의 ID 값을 갖는다. 따라서(contract address, uint256 tokenId)
는 이더리움 체인에서 유일함을 보장한다. UUID, SHA3 등의 결과값이 32bytes 이기 때문에 uint256과 호환성이 좋다. - Transfer Mechanism
- 컨트랙트가 중지되었을 때 불허해야함.
- 허가되지 않은 NFT, 컨트랙트 등이 전송에 개입할 때 불허해야함.
- unsafe 한 전송일 때 불허해야함.
- 거래에 참여하는 양쪽에 요금을 부과해야함.
- 거래가 실패한 경우는
ERC-223
,ERC-677
,ERC-827
,OpenZeppelin’s implementation of SafeERC20.sol
등 참고해서 구현하도록 할것. - NFT를 생성하고 없애는 것에 대한 명세는 포함되지 않음.
event
관련 문서를 참고할 것.
- ERC-165 Interface
: 적용된 인터페이스가 무엇인지 공개하도록 정의된 ERC-165(Standard Interface Detection) 를 구현해야한다. - Gas and Complexity (regarding the enumeration extension)
: for, while 루프를 사용하지 말 것. enumeration function 에 for-loop 대신 솔리디티 배역 타입을 반환하도록 하는 것이 가스 사용량 측면에서 안전함. - Privacy
: 모든 토큰id 에 대해 ownerOf 함수를 호출하면 소유자를 쉽게 알 수 있기 때문에, privacy는 보장할 수 없다. - Metadata Choices
: metadata extension을 통해name
과symbol
을 정의할 수 있는데, 빈문자열도 가능하고 다른 NFT와 중복되게 설정할 수 있다. web3 컨트랙트를 통해서만 호출할 수 있다.
Backwards Compatibility
ERC-20 과의 호환성을 위해 몇 함수를 인터페이스에 포함시켰다.
Implementation
- CryptoKitties : https://mangkyu.tistory.com/79
'BlockChain > Blockchains' 카테고리의 다른 글
비잔틴 장애 허용 문제 (0) | 2022.12.14 |
---|---|
[Klaytn] 합의알고리즘 (1) | 2022.12.14 |
[Hyperledger Fabric] 개념 정리 및 활용 프로젝트 예시 (0) | 2022.08.22 |
EIP-1155: Multi Token Standard (0) | 2022.08.12 |
비트코인이란? (Bitcoin WhitePaper 정리) (0) | 2022.08.04 |