Web Dev/Web3

Web3 :: 10주 챌린지 1주 - 스마트 계약서 작성, 첫 NFT 민트

HJPlumtree 2022. 5. 11. 15:16

Web3 / 웹3 10주 챌린지에서 배운 내용

 

 

Web3 10주 챌린지 시작!!

첫 주의 키워드

Solidity, 스마트 계약서(Smart contract), 테스트넷(testnets)

 

 

이번 차시에서 할 내용

  1. OpenZeppelin 과 Remix IDE 사용해서 스마트 계약서 작성
  2. rinkebyfaucet.com 이용해서 무료 Rinkeby ETH 받기
  3. 이더리움 테스트넷 블록체인에 배포해서 가스비 안쓰기
  4. Filebase 사용해서 IPFS에 NFT 토큰 호스트(host)하기
  5. NFT 민트하고 OpenSea에서 확인하기

 

 

우선 용어부터 알아보자

 

 

스마트 계약서(Smart Contract)

노드(서버)의 탈중앙 네트워크에서 돌아가는 소프트웨어의 부분

작성된 코드에 따라 트랜잭션이 이루어진다

 

스마트 계약서 작성시 필요한 것

  • Solidity(Ethereum) / Rust(Solana)
  • A Node(여기선 Alchemy(무료)를 사용한다, 직접 소프트웨어 다운받아서 구성해도 되지만, 오래 걸리니 이런 node 제공자를 이용하자)
  • 개발 환경(여기선 온라인 Remix IDE를 이용한다. 스마트 계약서를 위해 나온거라 훨씬 편하게 개발가능) 
  • 가스비 내기 위한 크립토화폐(Cryptocurrency) 

 

 

가스비(Gas Fee)

블록체인에서 모든 작동에 가스비를 내야한다.

예를 들면) 스마트 컨트랙트의 트랜잭션, 민트 등

 

이번에는 Rinkybe 테스트넷을 이용해서 스마트 계약서를 배포를 한다

테스트넷이라 실제 가스(돈)가 들어가지 않는다

 

 

민트(Mint)

새로운 것을 블록체인에 쓰는 것

새로운 입구를 블록체인에 만들어 주는 것

새로운 NFT를 블록체인에 만들어 주는 것

.. 등등

이렇게 블록체인에 무언가를 만들어서 접근하는 것

물론 가스비가 든다

 

 

Open Zeppelin

광대한 레포지토리 for 스마트 계약서

이미 검증된 안전한 라이브러리를 사용할 수 있다.

직접 스마트 계약서를 만들어도 되지만, 보안을 위해서 이렇게 검증된 것의 사용이 좋아보인다

얼마나 좋은가!

 

손쉽게 ERC20, ERC721, ERC11555 ... 등 스마트계약서 보일러플레이트를 얻을 수 있다

 

  • ERC20
    토큰을 만들 때 기준
  • ERC721
    NFT 만들 때 기준
  • ERC1155
    인벤토리, 게임 등에 이용하고
    ERC20, ERC721 둘 다 저장될 수 있다고 한다

 

 

실습 시작!
우선은 스마트 계약서만들기!

 

 

OpenZeppelin에서 ERC721로 이용해서 NFT 컬렉션을 만들 것이다

이렇게 원하는 설정을 해주고, 스마트 계약서의 틀을 만들 수 있다

 

그런 다음, Open in Remix 클릭하면, 스마트 계약서를 위한 온라인 Remix IDE로 이동한다

 

이 중에 가장 중요한 것은

민트를 해주는 _safeMint(to, tokenId) 함수

그리고 토큰을 지정해주는 _setTokenURI(tokenId, uri); 

자세한 내용은 _safeMint 문서, _setTokenURI 문서 참고

 

 

전체 코드

코드에 관한 설명은 주석으로 만들었다.

이게 Solidity라는 언어로 자바스크립트랑 크게 달라보이진 않는다

 

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

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

// 이니셜라이징 계약서 OOP 클래스랑 비슷
// 즉 계약서 HEEJAE는 ERC721, ERC721Enumerable 스마트 계약서 등을 interitance 한다

contract HEEJAE is ERC721, ERC721Enumerable, ERC721URIStorage {

    // 카운터 라이브러리 이니셜라이징
    using Counters for Counters.Counter;

    // 카운터 변수를 private로 만든다 
    // private로 만들어진 변수, 함수 등 모든 것들은 이 계약서에서만 보이고 사용된다
    Counters.Counter private _tokenIdCounter;

    // ++ NFT 컬렉션보다 더 많은 민트를 못하게 막아주기
    uint256 MAX_SUPPLY = 10000;

    // 생성자로 ERC721 인스턴스 생성하면서 이름과 심볼 지정
    constructor() ERC721("HEEJAE", "HEJ") {}

    // 제일 중요!!
    // 새로운 NFT를 블록체인에 만드는 함수
    // address(nft 보낼 장소), token uri, id를 이용한다
    // public은 어디서든 접근 가능
    // onlyOwner: 스마트 계약서한테 이 스마트 계약서를 배포한 사람이 아니면 차단하라는 의미
    // 누구나 NFT 민트를 하게 하려면 onlyOnwer, import Ownable도 지워주면 된다
    function safeMint(address to, string memory uri) public {

        // 현재 토큰ID를 tokenId에 저장
        uint256 tokenId = _tokenIdCounter.current();
        // ++ NFT 컬렉션보다 더 많은 민트를 못하게 막아주기
        require(tokenId <= MAX_SUPPLY, "I'm sorry all NFTs have been minted");
        // NFT 카운트
        _tokenIdCounter.increment();
        // tokenId를 to로 안전하게 민트해준다
        _safeMint(to, tokenId);
        _setTokenURI(tokenId, uri);
    }

    // The following functions are overrides required by Solidity.

    function _beforeTokenTransfer(address from, address to, uint256 tokenId)
        internal
        override(ERC721, ERC721Enumerable)
    {
        super._beforeTokenTransfer(from, to, tokenId);
    }

    function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) {
        super._burn(tokenId);
    }

    function tokenURI(uint256 tokenId)
        public
        // view를 지정해놓으면, 다른 스마트계약서가 아니라 본인 지갑에서 가져와서 No Gas Fee!
        view
        override(ERC721, ERC721URIStorage)
        returns (string memory)
    {
        return super.tokenURI(tokenId);
    }

    function supportsInterface(bytes4 interfaceId)
        public
        view
        override(ERC721, ERC721Enumerable)
        returns (bool)
    {
        return super.supportsInterface(interfaceId);
    }
}

 

이러면 스마트 계약서의 코드는 완성!!

 

 

블록체인 노드를 만들자!

 

 

Web3 앱을 만드려면 블록체인 노드(Nodes)가 필요하다.

직접 만드는 방법은 시간도 오래걸리고, 여러 문제가 생길 수 있다고 한다.

그래서 노드를 제공하는 Node Provider라는 곳을 이용하는데 Alchemy도 그 중 하나다.

 

여기서는 Alchemy를 이용한다(10주 챌린지도 Alchemy가 진행)

Alchemy에 들어가서, 테스트를 위해 rinkeby 네트워크로 앱을 하나 만들어준다

 

만든 앱에서 'VIEW KEY'를 눌러서 HTTP를 복사

 

 

Metamask에서 새로운 네트워크 추가

아까 복사한 HTTP를 RPC URL에 붙여넣고, Rinkeby 체인 ID(4)를 입력해준다

 

 

 

 

 

Rinkeby ETH를 받을 차례

 

 

말했듯이 블록체인에 무언가를 하면 가스비가 발생한다.

테스트넷에서도 똑같이 진행되기에 테스트용으로 사용할 수 있는 ETH를 받자.

 

RINKEBY FAUCET으로 이동해서 방금 연결한 메타마스크 주소를 적어주면,

꽤 금방 Rinkeby ETH가 온다. Alchemy 계정에 로그인 하면 0.1 -> 0.5로 올려서 준다.

 

 

따단! 0.5 Rinkeby ETH 도착

 

 

 

스마트 계약서 컴파일 & 배포!

 

 

컴파일하고 배포까지 달리자

변경시 자동으로 컴파일 되도록 Auto compile 체크해준다

컴파일이 잘 되고 있으면 왼쪽에 초록 체크표시가 보인다.

세미콜론을 빼먹지 않도록 주의

 

 

배포(Deploy)의 시간

Metamask를 이용해서 VM이 아니라 실제 블록체인에 배포가 가능하다

지금 만든 계약서를 선택 그리고 Deploy!

 

한번 더 블록체인에 무언가를 하려면 가스비가 들어간다

즉, 블록체인에 계약서를 배포하는 것도 가스비가 들어간다

메타마스크에서 예상 가스비를 알려준다

 

배포 완료!

왼쪽에 Deployed Contracts가 있으면 배포가 완료된 것이다.

or

etherscan에서 트랙잭션을 확인할 수 있다

 

 

첫 NFT 민트하기!

 

 

민트를 하기 위해서는 우선 메타데이터(metadata)를 만들어야 한다

Opensea에서 메타데이터 기준을 제공한다

 

메타데이터를 만들어 줄 때,

본인에게 편한 IDE를 사용하거나, 이런 온라인 JSON 에디터 사용해도 좋을 듯

메타데이터에 description, external_url, image 등을 넣어주는데

 

image를 업로드 하는 곳으로 filebase라는 곳을 이용한다.

filebase는 IPFS에 접근할 수 있도록 도와주는 사이트

 

IPFS는 호스팅 사이트라고 보면 되는데, 탈중앙 시스템에서 사용되는 파일 보관장소이다.
IPFS에 이미지를 올리면 이미지는 변경될 수 없게 한다.
filebase은 무료!

 

filebase에 로그인을 했다면, Bucket(버켓)을 만들어준다

버켓은 파일, 이미지 등을 저장할 공간으로, 소문자만 입력 가능하다.

저장 네트워크로는 IPFS선택

 

사용할 이미지는 Alchemy에서 제공한 예시 이미지를 사용한다.

ERC721

 

 

업로드 완료

IPFS Gateway URL이 생성되고, 이 주소를 메타데이터의 image에 사용한다

 

이름(name)도 입력하고,

trait_type은 Opensea에 들어가보면 Properties 밑에 표시되는 것을 정의한다.

 

 

이렇게 메타데이터를 전부 구성했으면 저장!

여기서는 온라인 에디터를 사용했으니 이렇게 

 

메타데이터 예시

Attributes에 원하는 내용을 채워주면 된다.

{
  "description": "This NFT proves I've deployed an ERC721 Smartt Contract on Rinkeby", 
  "external_url": "https://alchemy.com", 
  "image": "https://ipfs.filebase.io/ipfs/bafybeihyvhgbcov2nmvbnveunoodokme5eb42uekrqowxdennt2qyeculm", 
  "name": "ERC721 PoK",
  "attributes": [
    {
      "trait_type": "Chocolate", 
      "value": "A lot"
    }, 
    {
      "trait_type": "Website", 
      "value": "alchemy.com"
    }, 
    {
      "trait_type": "Token standard", 
      "value": "ERC721"
    }, 
    {
      "trait_type": "Level", 
      "value": 5
    }
  ]
}

 

 

메타데이터도 IPFS로 업로드

 

 

이렇게 만든 메타데이터도 filebase에 올려준다

업로드가 잘되면 CID를 복사한다

 

Opensea 공식 문서를 보면 CID를 이렇게 사용한다고 나온다 

ipfs://여기에 CID 입력

 

 

이제 진짜로 NFT 민트를 해보자!

 

 

복사한 ipfs 주소를 Remix IDE로 들어가서 safeMint의 url에 넣어준다

위의 to는 연결한 메타마스크 주소를 적어준다

 

그런 다음 transact 클릭!

 

transact를 클릭하면 배포 때처럼 메타마스크가 켜지고 예상 가스비가 나오고 확인을 누르면 된다 

 

배포와 마찬가지로 etherscan에서 확인

or

왼쪽 balanceOf에 메타마스크 주소를 넣어서 call을 눌러 nft가 하나 생긴 것을 확인

or

tokenURL에 0(지금 하나 만들었으니까 0번째)을 입력하면 확인할 수 있다

 

🥳🥳🥳 경축 첫 NFT 민트 완료! 🥳🥳🥳

 

 

민트한 NFT를 Opensea에서 확인하자!

 

 

이 NFT를 Opensea에서 어떻게 확인할까?

금방 민트는 테스트넷에서 진행해서 진짜가 아니지만 진짜처럼 확인할 수 있다!

바로 Opensea 테스트넷 이용하는 것이다.

 

Opensea testnets에 로그인을 하면 방금 민트한 NFT를 확인할 수 있다

 

 

1주차 정리를 해보자

OpenZeppelin으로 스마트 계약서를 만들었고,
스마트 계약서를 올리기 위해 무료 Rinkeby ETH를 받아서 Rinkeby 네트워크에 배포를 했다.
계약서를 이용해서 NFT 민트를 하고 Opensea 테스트넷에서 확인까지 완료했다.

 

 

참고 링크

How to develop an NFT Smart Contract (ERC721) with Alchemy [Youtube]

=> https://www.youtube.com/watch?v=veBu03A6ptw&list=TLPQMDEwNTIwMjIuPY0StW4EGA&index=2

 

위에 유튜브 블로그 버전

=> https://docs.alchemy.com/alchemy/guides/how-to-develop-an-nft-smart-contract-erc721-with-alchemy

 

1주차 완료 코드

=> 리믹스 온라인 IDE