동현 유
척척석사
동현 유
전체 방문자
오늘
어제
  • 분류 전체보기 (181)
    • BlockChain (48)
      • [paper] Consensus (13)
      • [paper] Execution (19)
      • [paper] Storage (5)
      • [paper] ZKP (1)
      • [paper] Oracle (1)
      • Blockchains (9)
    • Java (19)
      • Java의 정석 (13)
      • Java 파헤치기 (5)
    • Python (20)
      • Python 뜯어보기 (6)
      • 데이터 분석 기초 (5)
      • Python 기초 강의 (6)
      • Python 기초 강의 부록 (3)
    • Golang (0)
    • MySQL (3)
      • programmers (2)
      • 기본 문법 (0)
    • 웹 프로젝트 (IBAS) (36)
      • Django 레거시 (14)
      • SpringBoot api 개편 (14)
      • Infra (3)
      • 서버 장애 기록 (4)
      • 신입팀원 교육 자료 (1)
    • CS (30)
      • Operating System (22)
      • Computer Security (3)
      • Network (4)
      • DBMS (1)
    • 책 (10)
      • 도메인 주도 설계 철저 입문 (9)
      • Real MySQL 8.0 (1)
    • BOJ 문제 풀이 (3)
    • 이러쿵저러쿵 (10)
    • 회고 (1)

인기 글

최근 댓글

최근 글

hELLO · Designed By 정상우.
동현 유
BlockChain/Blockchains

EIP-721: Non-Fungible Token Standard

BlockChain/Blockchains

EIP-721: Non-Fungible Token Standard

2022. 8. 12. 15:27

Abstract

스마트 컨트랙트 내에서 NFT의 표준 API 인터페이스를 규정. 표준 API는 NFT를 교환하고 기록하기 위한 기본적인 기능을 제공한다.

NFT는 다음과 같은 다양한 디지털 또는 물리 자산에 대한 소유권을 나타낼 수 있다.

  • 물리 자산 - 집, 예술 작품 등
  • 수집품 - 유일성이 보장되는 수집용 카드 등
  • 대출과 같은 마이너스 자산 등

NFT는 구별 가능한 디지털 토큰으로서 각 자산에 대해 개별적으로 소유권을 추적할 수 있도록 한다.

Specification

  • ERC-721를 따르는 컨트랙트를 만들기 위해서는 ERC721, ERC165 인터페이스를 반드시 구현해야한다.
        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);
        }
        ```
    view raw [EIP-721] interface.md hosted with ❤ by GitHub
  • 어플리케이션은 지갑 인터페이스를 구현해야한다.
    /// @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);
    }
    view raw [EIP-721] ERC721TokenReceiver.md hosted with ❤ by GitHub
  • (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);
    }
    view raw [EIP-721] ERC721Metadata.md hosted with ❤ by GitHub
    // "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."
    }
    }
    }
    view raw [EIP-721] metadata.json hosted with ❤ by GitHub
  • (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);
    }
    view raw [EIP-721] ERC721Enumerable.md hosted with ❤ by GitHub

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
  • Abstract
  • Specification
  • Rationale
  • Backwards Compatibility
  • Implementation
동현 유
동현 유
Fault Tolerant System Researcher for more Trustful World and Better Lives. (LinkedIn: https://www.linkedin.com/in/donghyeon-ryu-526b8a276/)
척척석사Fault Tolerant System Researcher for more Trustful World and Better Lives. (LinkedIn: https://www.linkedin.com/in/donghyeon-ryu-526b8a276/)

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.