NFT를 발급해보자!

NFT

Non-Fungible Token!

ERC?

ERC란, Ethereum Request for Comments의 약자로 스마트 컨트랙트를 위한 표준 규격을 정의한다.

  • 개발자들이 블록체인 상에서 동일한 프로토콜로 작업할 수 있도록 표준화된 인터페이스 제공
  • 상호 운용성 & 호환성 보장

ERC-20 & ERC-721?

ERC-20

개념

  1. 대체 가능한 토큰을 발행하기 위한 표준
  2. 대체 가능하다는 뜻은, 모든 토큰이 동일한 가치와 특성을 지님

특징

  1. 암호화폐나 유틸리티 토큰 발행에 사용됨
  2. 토큰간의 차별성이 없으므로, 화폐처럼 동일한 가치로 교환

사용예

  • 유동성 토큰
  • 스테이블 코인

필수 함수

  • totalSupply() : 토큰 총 공급량
  • balanceOf(address) : 특정 주소 잔액 확인
  • transfer(addr, uint) : 토큰 전송
  • approve(addr, uint) : 지갑/ 스마트 컨트랙트 권한 부여
  • transferFrom(addr, addr, uint) : 권한 받은 토큰 전송

ERC-721

개념

  1. ERC-721는 대체 불가능한 토큰을 발행하기 위한 표준
  2. 대체 불가능하다는 뜻은, 각각의 토큰이 고유한 속성을 가져, 서로 동일하지 아니함

특징

  1. ERC-721 토큰은 “독립적인 고유 ID”를 가진다.
  2. 따라서 고유하고, 독립적인 가치를 가진다 (== 다른 토큰과 교환될 때 동일한 가치가 아님)

사용예

  • 디지털 아트
  • 게임 아이템
  • …etc

필수 함수

  • ownerOf(uint) : 특정 토큰 ID의 소유자 확인
  • transferFrom(addr, addr, uint): 토큰 전송
  • toeknURI: : 토큰의 메타 데이터 URI 반환 : NFT의 실제 이미지나 데이터를 저장하는 URL을 저장함
    • 이유 : 실제 이미지를 블록체인 네트워크에 올린다면, 가스비가 매우매우 부담됨

간단 요약

특징 ERC-20 ERC-721
대체 가능성 대체 가능 대체 불가능
사용 목적 암호화페, 유틸 디지털 자산, NFT
고유성 동일함 고유한 ID
스마트 계약 단일 주소, 여러 토큰 개별 토큰, 개별 주소

ERC-1155??

게임 아이템과 같은 대체 가능 토큰 && 대체 불가능 토큰 둘 다 관리하는 유연한 구조를 제공

(추후 작성할게요)

NFT 발급 smart contract 작성해보기

목적: 토큰을 발급하고, 이미지를 저장해보기

  1. 이미지를 저장하기 위해 @openzeppelin의 ERC-721/extensions/ERC721URIStorage를 사용했다.
  2. 이해는 잘 못했지만, 업그레이드 가능한 컨트랙트를 작성하기 위해 upgradeable을 적용했다. + proxy.sol 존재 프록시 패턴 하나로도 글이 5개 넘게 나올 것 같다…. 선배님들 알려주세요… 너무 어려워요..

ERC-721 과 관련된 ERC721 & ERC721URI 그리고 ERC721ENUM은 추후 새로운 컨트랙트 배포를 위해 사전작업으로 분석하는 포스팅을 하고자 합니다.

내가 작성한 코드

해당 코드는 중복 구현된 기능이 많습니다.

따라서 가스비는 최악이며…

메서드 또한 중복되는 요소가 많아 사용하기에 불편합니다.

뉴비가 새롭게 배우는 과정으로 가볍게 읽어주세요.

contract MyNFTV4 is ERC721URIStorageUpgradeable, OwnableUpgradeable {
    uint256 private _tokenIds;

    // v3
    // 중복구현!
    // ERC721 표준에서 이미 소유자와 관련된 정보를 제공함...
    mapping(address => uint256[]) private _ownedTokens;


    // 업그레이드 가능한 컨트랙트를 실행하기 위함. 반드시 사용!
    function initialize() external initializer {
        __ERC721URIStorage_init();
        __ERC721_init("MyNFT", "YooNFT");
        __Ownable_init(msg.sender);
    }

    // 중복구현요소가 있을 수 있음.
    function mintNFT(
        address recipient,
        string memory tokenURI
    ) public returns (uint256) {
        _tokenIds++; // Solidity 0.8 이상에서는 오버플로우 체크가 자동임.
        uint256 newTokenId = _tokenIds;

        _mint(recipient, newTokenId); // 새로운 NFT 발행 (recipient, tokenId)
        _setTokenURI(newTokenId, tokenURI); // 해당 tokenId에 대한 URI 설정

        // 중복구현!
        // 위에서 말한 이유와 같다..ㅠㅠ
        _ownedTokens[recipient].push(newTokenId); // v3

        return newTokenId; // 발행된 새로운 NFT의 tokenId 반환
    }

    // v3
    // 중복? 기능문제? : ownerOf로 파악은 가능하지만, 소유자별 토큰 목록을 반환함.
    // 가스비 이슈는 피하기 힘들 것 같다.
    function getNFTsByOwner(
        address owner
    ) external view returns (uint256[] memory) {
        return _ownedTokens[owner];
    }

    // 총 발행된 NFT의 수량을 반환함
    function totalMintedNFTs() external view returns (uint256) {
        return _tokenIds;
    }


    // 중복구현!!
    // ERC721URI에 이미 toeknURI라는 함수가 존재하여, 의미 없음...
    function getTokenURI(
        uint256 tokenId
    ) external view returns (string memory) {
        return tokenURI(tokenId);
    }

중복 구현에 대한 조금 더 자세한 설명…

  1. ownedTokens 매핑 + 소유자 매핑 업데이트
  • 중복 데이터 관리임..
  • balanceOf를 통해 접근해보는건 어떨까.
  1. getTokenURI는 이미 balanceOf가 있는 것 같으니 이를 이용해보자.
  2. event 혹은 외부에 기록되는 컨트랙트 내부의 이력을 추적하여, 따로 기록한다면 가스비를 절약할 수 있지 않을까..?

결론…

생각보다 너무 어렵다.

정말 어렵다.

생태계가 생각보다 많이 방대하기도 하고…

하나를 공부하면 공부하고 알아야 하는 것이랑, 바꾸기 쉽지 않다는 이슈로 인해 머리가 너무 뜨거워지는게 느껴진다.

아무래도… 하나하나 파면서 정공법으로 도전하는 수 밖에 없지 않을까합니다..

따라서 다음 시간에는 ERC-721을 한번 분해해보겠습니다…

부족한 글 읽어주셔서 감사합니다.

ㅠㅠ 2025-01-08. 힘내볼게요.