Truffle을 이용한 ERC-721 개발

Enzo·2022년 4월 7일
0

블록체인

목록 보기
20/21

이번 프로젝트는 Truffle 프레임워크를 이용하여 Local 환경에서 NFT개발을 해보려고 한다.
가나슈를 사용하여 로컬에서 테스트해도 되지만 OpenSea에서 실제 NFT를 확인하기 위해 rinkeby 테스트넷에 배포를 하려고 한다.

개발에 들어가기전 기본적으로 알고 진행하면 좋은 개발 툴들에 대해서 설명하겠다.

Truffle

Truffle은 프레임워크로 스마트 컨트랙트 개발시 개발, 배포 및 테스트 환경을 제공 한다.
node.js에서 동작하기 때문에 자바스크립트를 자주 사용했던 나는 좀 더 익숙하게 사용할 수 있었다.

설치 명령어

npm install -g truffle

Truffle Develop으로 자체적으로 이더리움 클라이언트를 제공하기 때문에 스마트컨트랙트를 쉽게 배포하고 테스트 해볼 수 있다.

또한 Ganache, MetaMask 계정에 연동하여 사용도 가능하다.

Ganache

이더리움 노드는 네트워크에 접속하여 모든 블록을 동기화시켜야 한다.
이는 무겁고 오래걸리는 작업이므로 스마트컨트랙트 개발에 장애물이 될 수 있다.

가나슈는 이런 불편한 점들을 해결하고자 Local 네트워크에서 배포, 테스트 등을 해볼 수 있는 환경을 제공해준다.

가나슈 등을 이용해 만든 가상 환경을 TestRPC라고 한다.

MetaMask와 연동하여 사용할 수도 있다.

Open Zeppelin 라이브러리

스마트 컨트랙트 개발에서 사용되는 라이브러리로 FT와 NFT의 표준 코드 등 스마트컨트랙트 개발에서 가장 많이 쓰이는 코드들을 모듈처럼 가져다 쓸 수 있기 때문에 필수적인 요소이다.


개발

개발 환경 세팅

erc721 디렉토리를 만들고 truffle init을 통해 트러플을 초기화 한다.

mkdir erc721
cd erc721
truffle init
npm init

먼저 사용할 솔리디티 버전과 컴파일러 버전을 수정해주어야 한다.
truffle-config.js를 열고 수정해주면 된다.

이후 rinkeby 네트워크에 연결하기 위해 세팅을 진행한다.
해당 세팅은
https://www.geeksforgeeks.org/deploying-smart-contract-on-test-main-network-using-truffle/
를 참고 하였다.

rinkeby 테스트넷에 배포하기 위해 필요한 조건은 infura에서 받은 엔드포인트와 @truffle/hdwallet-provider 모듈, 메타마스크 지갑의 니모닉 코드가 필요하다.

const HDWalletProvider = require("@truffle/hdwallet-provider");
const fs = require("fs");
const Seed_phrase = fs.readFileSync(".mnemonic").toString().trim();

networks:{
	rinkeby: {
      provider: () =>
        new HDWalletProvider(
          Seed_phrase,
          `https://rinkeby.infura.io/v3/4b0de5f9557d40449513e41961808e83`
        ),
      network_id: 4, // Ropsten's id
      gas: 5500000, // Ropsten has a lower block limit than mainnet
      confirmations: 2, // # of confs to wait between deployments. (default: 0)
      timeoutBlocks: 200, // # of blocks before a deployment times out  (minimum/default: 50)
      skipDryRun: true, // Skip dry run before migrations? (default: false for public nets )
    },
}

컨트랙트 작성

환경에 대한 세팅이 다 되었다면 컨트랙트를 작성하면 된다.

openzeppelin라이브러리를 다운 받고 ERC721URIStorage와 Ownable을 상속받아 MyNFTs 라는 컨트랙트를 작성하였다.

//Contract based on [https://docs.openzeppelin.com/contracts/3.x/erc721](https://docs.openzeppelin.com/contracts/3.x/erc721)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;

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

contract MyNFTs is ERC721URIStorage, Ownable {
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;

    constructor() public ERC721("MyNFTs", "MNFT") {}

    function mintNFT(address recipient, string memory tokenURI)
        public onlyOwner
        returns (uint256)
    {
        _tokenIds.increment();

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

        return newItemId;
    }
}

컨트랙트 코드작성을 했다면 배포를 위해 /migrations/1_initial_migration.js 파일을 수정해주어야 한다.

const Migrations = artifacts.require("Migrations");
const MyNFTs = artifacts.require("MyNFTs.sol"); //MyNFTs 추가

module.exports = function (deployer) {
  deployer.deploy(Migrations);
  deployer.deploy(MyNFTs);//MyNFTs 추가
};

컨트랙트 배포

이제 작성한 코드를 컴파일 후에 rinkeby네트워크에 배포한다.

truffle migrate --compile-all --network rinkeby

성공적으로 배포를 하게 되면 터미널에 배포된 내용이 출력되고 이때 트랜잭션 해쉬를 이더스캔에서 확인이 가능하다.

이더스캔 rinkeby네트워크 배포 트랜잭션 내용

verify & publish

truffle 환경에서는 oppenzepplin 라이브러리를 사용한 것을 모두 잡아주지 않는 것 같았다.
그래서 truffle-flattener를 이용해서 한 파일에 사용한 모든 컨트랙트를 불러오는 작업을 해주어야한다.
해당 내용은
https://forum.openzeppelin.com/t/how-to-flatten-and-verify-a-smart-contract-using-openzeppelin-contracts/1119
를 참고하였다.

npx truffle-flattener ./contracts/MyNFTs.sol > ./contracts/FlatMyNFTs.sol

명령어를 통해 사용한 모든 컨트랙트를 담은 하나의 파일이 생성된다.
이때 SPDX가 여러개가 되어 오류가 날 수 있으므로 맨 위에 SPDX만 남기고 모두 지워주었다.
verify & publish 할때 flat하게 생성된 파일 코드를 붙여넣게 되면 성공적으로 verify & publish가 이루어진다.

NFT 발행

이제 배포된 컨트랙트의 함수를 이용하여 NFT를 발행할 수 있다.
mintNFT 함수에 받을 사람 주소와 tokenURI를 넣어주면 발행이 된다.

tokenURI에 NFT에 사용될 메타데이터를 넣게 되는데 이떄 나는 pinata라는 IPFS 네트워크를 사용하였다.

NFT 발급이 정상적으로 진행된 것을 확인할 수 있다.


github 주소와 컨트랙트 주소

github
contract


회고

좋았던 점

크립토 좀비를 진행하면서 솔리디티에 점점 익숙해져가고 실제로 토큰과 NFT를 발급해보면서 흐름을 익힌 것 같다. 한글로 된 자료가 많이 부족하여 막히는 부분이 생기면 영어로 된 자료들을 찾게 되는데 이러한 과정이 처음에는 낯설었지만 점차 적응되어 가는것 같아서 좋은 것 같다.

어려운 부분

truffle을 사용해서 rinkeby 네트워크에 연결하는 자체가 너무 어려웠다. 실습때 remix를 사용했을때는 너무 간단하게 느껴졌었는데 신경써야 할 부분이 엄청 많았고 계속 막혀서 많은 시간을 할애해야 했다. 로컬환경에서 테스트하기에는 좋은 것 같지만 테스트넷에 연동해야 한다면 굳이 사용하지는 않을 것 같다... remix 만세를 느낀 하루였다.

개선할 점

연습 겸 간단한 개발 프로젝트였기 때문에 구글에 아무 사진이나 퍼와서 NFT를 만들었지만 좀 더 고도화된 내용과 작품성있는 이미지가 들어간다면 충분히 가치를 가질 수 있을 것 같다.

의문점

NFT를 발급할때 IPFS 네트워크와 같이 어딘가에 업로드를 하고 그 URI를 복사해서 metadata를 만들었다. 그렇다면 원본 이미지의 URI가 어딘가에 업로드 되어있다는 것인데 NFT가 의미가 있어지는지 의문이 들었다. 업로드 없이 바로 metadata를 생성하는 방법이 있는지 찾아봐야겠다.

profile
고통수집가

0개의 댓글