ERC-721과 NFT 개발

Yona·2022년 1월 24일
3

블록체인

목록 보기
16/22
post-thumbnail

Introduction

Achievement Goals

  • ERC-721과 ERC-20의 차이점을 설명할 수 있다.
  • ERC-721에 포함된 함수별 기능을 이해할 수 있다.
  • ERC-721을 통한 NFT가 사용되는 방식을 설명할 수 있다.
  • NFT를 거래 또는 사용하는 플랫폼을 설명할 수 있다.
  • NFT의 거래 또는 사용 방식을 이해할 수 있다.
  • Remix, Truffle을 이용해 직접 ERC-721을 배포할 수 있다.
  • IPFS와 연동하여 NFT에 이미지를 저장하고, 배포할 수 있다.
  • 클레이튼 기반의 NFT와 이더리움 기반의 NFT를 비교할 수 있다.
  • 클레이튼 테스트넷에 NFT를 배포할 수 있다.
  • OpenSea에서 클레이튼 기반의 NFT와 이더리움 기반의 NFT를 거래할 수 있다.
  • Minting 플랫폼으로 NFT를 하는 방법을 이해할 수 있다.

📔 ERC-721

ERC-721 이란...
: 2018년 1월 William Entriken, Dieter Shirley, Jacob Evans, Nastassia Sachs 의 EIP-721 제안의 의해 2018년 6월 최종적으로 승인 받아 탄생하게 되었다.
erc721을 요약하자면, 증서라고 하는 대체 불가능한 토큰에 대한 표준을 정의한 것이다.

+ Dieter Shirley는 CrpyotoKitties 를 제작하였으며, Dapper Labs의 설립자이자 Flow라는 블록체인의 설계까지 한 뛰어난 사람이다...

  • ERC-721은 NFT를 추적하고 전송하는 기본 기능을 포함한다
  • 고유한 속성을 지니고, 각각 구별할 수 있으며 소유권을 별도로 추적할 수 있어야 한다.

ERC-721 과 ERC-20을 구분하기 위해서는 ERC-165 자체 검사를 수행하여야 한다.

ERC-165 란...
스마트 컨트랙트가 구현하는 인터페이스를 게시하고 있는지 감지하는 표준 방법이다. EIP-165

‼️ 주의해야할 점 ‼️

  • 코드에서 for/while loop를 사용하지 말란다. 가스비가 무한으로 올라가는 이슈가있다고하니 필요한 경우에는 함수에서 solidity 배열 유형을 return 해주라고한다.
  • 모든 메타데이터를 온체인상으로 올리기에는 너무 비싸다.
  • nft에서의 고유 식별은 uint256의 ID로 식별이되기때문에 단순하게 순차적으로 증가하는 패턴보다는 "Black box"로 취급해야한다. (아무도 볼 수없게 하라는 뜻인듯?...)

⚙️ ERC-721 표준 소스코드

pragma solidity ^0.4.20;

interface ERC721 {
  event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
  event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);
  event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);

  function balanceOf(address _owner) external view returns (uint256); // 해당 주소가 보유하고있는 nft갯수를 리턴
  function ownerOf(uint256 _tokenId) external view returns (address); // nft를 소유하고 있는 주소를 리턴
  function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable;
  function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable; // 전송받는 to 주소가 erc721토큰을 받을수 있는지 체크하고 전달
  function transferFrom(address _from, address _to, uint256 _tokenId) external payable; // nft 소유자로부터 해당 nft를 다른 주소로 전송 
  function approve(address _approved, uint256 _tokenId) external payable; // 해당 주소에 nft 전송 권한을 부여
  function setApprovalForAll(address _operator, bool _approved) external; // nft 소유자가 해당 주소에게 모든 nft 에 대한 전송 권한 부여 및 해제
  function getApproved(uint256 _tokenId) external view returns (address); // 해당 토큰의 전송 권한을 갖고 있는 주소를 리턴
  function isApprovedForAll(address _owner, address _operator) external view returns (bool); // setApprovealForAll 의 권한이 있는지 true, false 리턴
}

interface ERC165 {
  function supportsInterface(bytes4 interfaceID) external view returns (bool);
}

⚙️ ERC-721 (TokenReceiver)

interface ERC721TokenReceiver {
  function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes _data) external returns(bytes4);
}

⚙️ ERC-721 (Metadata)

interface ERC721Metadata {
  function name() external view returns (string _name);
  
  function symbol() external view returns (string _symbol);
  
  function tokenURI(uint256 _tokenId) external view returns (string);
}

/*
위 ERC721 Metadata 의 JSON 스키마 형태
{
    "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."
        }
    }
}
*/

⚙️ /선택사항/ ERC-721 (Enumerable)

interface ERC721Enumerable {
  function totalSupply() external view returns (uint256);
  function tokenByIndex(uint256 _index) external view returns (uint256);
  function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256);
}

⚙️ 오픈재플린 ERC721 예제코드

// contracts/GameItem.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/utils/Counters.sol";

contract GameItem is ERC721URIStorage {
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;

    constructor() ERC721("GameItem", "ITM") {}

    function awardItem(address player, string memory tokenURI)
        public
        returns (uint256)
    {
        _tokenIds.increment();

        uint256 newItemId = _tokenIds.current();
        _mint(player, newItemId);
        _setTokenURI(newItemId, tokenURI);

        return newItemId;
    }
}

각 function 마다 주석으로 어떤 기능을 수행하는지 간략하게 적어두었으니 확인하자
ERC-721의 핵심은 uint256 => address 의 mapping 에 대해서 반드시 알아야함


💡 참고링크

1) https://eips.ethereum.org/EIPS/eip-721
2) https://github.com/ethereum/eips/issues/721
3) https://eips.ethereum.org/EIPS/eip-165#simple-summary
4) https://soliditydeveloper.com/erc-721
5) https://docs.openzeppelin.com/contracts/2.x/api/token/erc721
6) https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/ERC721.sol
7) https://anallergytoanalogy.medium.com/jumping-into-solidity-the-erc721-standard-part-1-e25b67fc91f3

2개의 댓글

comment-user-thumbnail
2022년 1월 30일

쉽게 잘 정리해주셨어요!

답글 달기
comment-user-thumbnail
2022년 2월 1일

쉽게 정리된 글을 통해 많은것을 알아갈 수 있게 해주셔서 감사합니다.

답글 달기