Truffle을 이용한 스마트 컨트랙트 배포 및 NFT 발행

HY·2022년 6월 9일
1

research

목록 보기
3/4
post-thumbnail

개념

ERC-721은 대체불가토큰(Non Fungible Token) NFT의 표준안이다.
Truffle은 이더리움 기반 dApp을 쉽게 개발할 수 있도록 도와주는 프레임워크이다.
블록체인에서 smart contract를 컴파일하고 배포하는데 사용할 수 있다.
openzeppelin은 안전한 smart contract 개발을 위한 라이브러리이다.
ERC-721, ERC-20 등과 같은 표준 구현에 사용된다.

개발

repository: https://github.com/haejeonghy/nft-truffle

. 디렉토리 구조
├── README.md
├── build
├── contracts
│   ├── Migrations.sol
│   ├── NewNFT.sol
│   └── artifacts
│       ├── NewNFT.json
│       ├── NewNFT_metadata.json
│       └── build-info
├── migrations
│   └── 1_initial_migration.js
├── node_modules
├── package-lock.json
├── package.json
├── test
├── test.json
└── truffle-config.js
  1. 개발에 사용될 리포지토리를 생성한다.
mkdir ha-ntf-truffle
❯ cd ha-ntf-truffle/
  1. Truffle과 npm을 초기화 한다.
npm init
❯ truffle init
  1. HDWalletProvider, dotenv를 설치한다.
npm i --save truffle-hdwallet-provider
❯ npm i dotenv
  1. solidity 파일을 컴파일 할 때 사용할 설정으로 컴파일러 설정을 변경한다.
// truffle-config.js
  compilers: {
    solc: {
      version: "0.8.7",      // Fetch exact version from solc-bin (default: truffle's version)
      // docker: true,        // Use "0.5.1" you've installed locally with docker (default: false)
      settings: {          // See the solidity docs for advice about optimization and evmVersion
      //  optimizer: {
      //    enabled: false,
      //    runs: 200
      //  },
       evmVersion: "london"
      }
    }
  },
  1. 로컬 환경에서 테스트할 때 사용할 ropsten로 네트워크 설정을 변경한다.
// truffle-config.js
var HDWalletProvider = require("truffle-hdwallet-provider");
require('dotenv').config()
const mnemonic = process.env.MNEMONIC
const infuraEndpoint = process.env.INFURA_ENDPOINT

networks: {
    ropsten: {
      provider: function() {
        return new HDWalletProvider(mnemonic, infuraEndpoint)
      },
      network_id: '*',
      gas: 30000000
    }
}
  1. contract/ 폴더에서 테스트할 solidity 파일을 생성한다.
// newNFT.sol
// 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 NewNFT is ERC721URIStorage, Ownable {
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;

    constructor() ERC721("HJ NFT", "HJN") {}

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

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

        return newItemId;
    }
}
  1. solidity 파일에서 참조한 OpenZeppelin 패키지를 설치한다.
npm i @openzeppelin/contracts

added 1 package, and audited 2 packages in 643ms

found 0 vulnerabilities
  1. 생성한 solidity 파일을 배포하기 위해 migration 파일에 설정을 추가한다.
//migration/1_initial_migration.js

const Migrations = artifacts.require("Migrations");
const NewNFT = artifacts.require("NewNFT");

module.exports = function (deployer) {
  deployer.deploy(Migrations);
  deployer.deploy(NewNFT);
};
  1. .env 파일을 생성하여 Metamask mnemonic과 infura ropsten endpoint를 작성한다.
//.env
MNEMONIC=
INFURA_ENDPOINT=
  1. Truffle로 배포한다.
❯ truffle deploy --network ropsten

Compiling your contracts...
===========================
> Compiling ./contracts/NewNFT.sol
> Artifacts written to /Users/yuhaejeong/Workspace/git/ha-ntf-truffle/build/contracts
> Compiled successfully using:
   - solc: 0.8.7+commit.e28d00a7.Emscripten.clang


Migrations dry-run (simulation)
===============================
> Network name:    'ropsten-fork'
> Network id:      3
> Block gas limit: 30000000 (0x1c9c380)


1_initial_migration.js
======================

   Deploying 'Migrations'
   ----------------------
   > block number:        12354706
   > block timestamp:     1654754062
   > account:             0xD74C244f3c9F5e05C0CA5344394F5A7247f0d1b9
   > balance:             69.30939778879727343
   > gas used:            250154 (0x3d12a)
   > gas price:           2.500000007 gwei
   > value sent:          0 ETH
   > total cost:          0.000625385001751078 ETH


   Deploying 'NewNFT'
   ------------------
   > block number:        12354707
   > block timestamp:     1654754067
   > account:             0xD74C244f3c9F5e05C0CA5344394F5A7247f0d1b9
   > balance:             69.302464148777859238
   > gas used:            2773456 (0x2a51d0)
   > gas price:           2.500000007 gwei
   > value sent:          0 ETH
   > total cost:          0.006933640019414192 ETH

   -------------------------------------
   > Total cost:     0.00755902502116527 ETH

Summary
=======
> Total deployments:   2
> Final cost:          0.00755902502116527 ETH




Starting migrations...
======================
> Network name:    'ropsten'
> Network id:      3
> Block gas limit: 30000000 (0x1c9c380)


1_initial_migration.js
======================

   Deploying 'Migrations'
   ----------------------
   > transaction hash:    0x790e53bbcf9cdb2c4d076717a1cec24b508eeb433e85fab4a09ea4d2711a5e9c
   > Blocks: 16           Seconds: 195
   > contract address:    0x73145d9F2466dECA1A4057f63404452Acc81E8D3
   > block number:        12354727
   > block timestamp:     1654754268
   > account:             0xD74C244f3c9F5e05C0CA5344394F5A7247f0d1b9
   > balance:             69.30964794279727343
   > gas used:            250154 (0x3d12a)
   > gas price:           1.500000007 gwei
   > value sent:          0 ETH
   > total cost:          0.000375231001751078 ETH


   Deploying 'NewNFT'
   ------------------
   > transaction hash:    0xef816c6dfca1f164c471f3a9fa2f479aeefec9c39904805171a859e622d430c3
   > Blocks: 3            Seconds: 29
   > contract address:    0x697C92161fC4772c290E9bBC9C2a13117c517dB1
   > block number:        12354730
   > block timestamp:     1654754304
   > account:             0xD74C244f3c9F5e05C0CA5344394F5A7247f0d1b9
   > balance:             69.305487758777859238
   > gas used:            2773456 (0x2a51d0)
   > gas price:           1.500000007 gwei
   > value sent:          0 ETH
   > total cost:          0.004160184019414192 ETH

   > Saving migration to chain.
   > Saving artifacts
   -------------------------------------
   > Total cost:     0.00453541502116527 ETH

Summary
=======
> Total deployments:   2
> Final cost:          0.00453541502116527 ETH
  1. Truffle console을 통해 ropsten에 진입한다.
❯ truffle console --network ropsten
truffle(ropsten)> 
  1. 배포한 contract의 인스턴스를 받아와 작성한 solidity 파일에서 입력한 NFT설정과 일치하는지 확인한다.
truffle(ropsten)> instance = await NewNFT.deployed()
undefined
truffle(ropsten)> instance.name()
'HJ NFT'
truffle(ropsten)> instance.symbol()
'HJN'
  1. 직접 그린 그림을 이미지 업로드 사이트에 업로드한다.
  2. 이미지 정보를 담은 test.json파일을 생성한다.
{
    "name": "The Cheese #1",
    "description": "first cheese cat",
    "image": "https://i.ibb.co/tKDBSgf/Kakao-Talk-Image-2022-06-09-12-40-29.png",
    "attributes": [
      {
        "trait_type": "Power",
        "value": "Max"
      }
    ]
  }
  1. Truffle console에서 NFT를 발행한다.
truffle(ropsten)> instance.mintNFT("/Users/yuhaejeong/Workspace/git/ha-ntf-truffle/test.json", { from: accounts[0] }){
  tx: '0xe7cb0476b379f15e9fa004cff8b26de9ade7d0d1bdc36cc559a45a7614cc0140',
  receipt: {
    blockHash: '0x663ec952faca79c12237c0766ce3b586800ccb385eb3735c457ff25088af69f7',
    blockNumber: 12354781,
    contractAddress: null,
    cumulativeGasUsed: 162429,
    effectiveGasPrice: '0x59682f07',
    from: '0xd74c244f3c9f5e05c0ca5344394f5a7247f0d1b9',
    gasUsed: 162429,
    logs: [ [Object] ],
    logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000040000000000000000000008000000000000000000040000000000000000000000000000020000000000000000000800000000000000000000000010000000000000000400001000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000060000000000000000000004000000000000000000800000000000000000000000000',
    status: true,
    to: '0x697c92161fc4772c290e9bbc9c2a13117c517db1',
    transactionHash: '0xe7cb0476b379f15e9fa004cff8b26de9ade7d0d1bdc36cc559a45a7614cc0140',
    transactionIndex: 0,
    type: '0x0',
    rawLogs: [ [Object] ]
  },
  logs: [
    {
      address: '0x697C92161fC4772c290E9bBC9C2a13117c517dB1',
      blockHash: '0x663ec952faca79c12237c0766ce3b586800ccb385eb3735c457ff25088af69f7',
      blockNumber: 12354781,
      logIndex: 0,
      removed: false,
      transactionHash: '0xe7cb0476b379f15e9fa004cff8b26de9ade7d0d1bdc36cc559a45a7614cc0140',
      transactionIndex: 0,
      id: 'log_ba1e9544',
      event: 'Transfer',
      args: [Result]
    }
  ]
}
  1. 발행한 NFT의 tokenURI를 확인한다.
truffle(ropsten)> instance.tokenURI(1)
'/Users/yuhaejeong/Workspace/git/ha-ntf-truffle/test.json'
  1. Etherscan에서 NFT 발행을 확인한다.
    https://ropsten.etherscan.io/tx/0xe7cb0476b379f15e9fa004cff8b26de9ade7d0d1bdc36cc559a45a7614cc0140
    Contract hash: 0x697C92161fC4772c290E9bBC9C2a13117c517dB1
    https://ropsten.etherscan.io/address/0x697c92161fc4772c290e9bbc9c2a13117c517db1

회고

NFT라고 하면 오픈씨와 같은 특정 플랫폼만 생각났는데 직접 만들어서 배포해보니 재밌었다.
나중에 NFT 플랫폼을 만들어보고 싶다.

참고 문헌

http://wiki.hash.kr/index.php/ERC-721
http://wiki.hash.kr/index.php/%ED%8A%B8%EB%9F%AC%ED%94%8C
https://docs.openzeppelin.com/contracts/4.x/
https://trufflesuite.com/docs/

profile
사실은 공부를 비밀스럽게 하고 싶었다

0개의 댓글