ERC721은 대체 불가능한 토큰(Non-Fungible Token)으로 흔히 말하는 NFT의 표준이다.
각 토큰은 고유하기 때문에, 각각의 가치를 가지고 있다.
openzepplin을 이용하면 간단하게 구현해볼 수 있다.
실습에 참고한 페이지는 openzepplin 공식 문서와 이 velog 글.
개발 환경을 위한 환경 세팅(truffle이나 hardhat을 이용해서)완료했다면 openzepplin 활용을 위해 openzepplin contract를 설치해준다.
$> npm install --save-dev @openzeppelin/contracts
설치가 완료되면 contracts 디렉토리에 solidity 파일을 생성해준다.
ERC721는 openzepplin에서 제공하는 ERC721을 상속 받아서 쉽게 구현할 수 있는데, 참고한 두 예제 모두 ERC721이 아닌 확장형인 ERC721URIStorage를 상속 받고 있어서 해당 contract를 상속 받아 구현해보았다.
ERC721URIStorage는 기존의 ERC721에서 tokenURI를 별도로 지정할 수 있는 기능이 추가된 확장형이다.
다만 더 비싼 가스비가 발생한다.
MyNFT.sol 👇
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;
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";
// openzeppelin의 ERC721 확장 버젼인 ERC721URIStorage 상속
// ERC721 == NFT
contract MyNFT is ERC721URIStorage, Ownable {
// 값의 증감만을 하기 위해 사용하는 타입
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
constructor () ERC721("MyNFT", "MFT") {}
function mintNFT(string memory tokenURI) public onlyOwner returns (uint256) {
_tokenIds.increment();
uint256 newItemId = _tokenIds.current();
_mint(msg.sender, newItemId);
_setTokenURI(newItemId, tokenURI);
return newItemId;
}
}
ERC721 구현을 위해 상속 받은 ERC721URIStorage외에 별도로 상속 받은 Ownable 역시 openzepplin에서 제공하는데 Ownalbe을 상속 받으면 contract에 ownership을 주입할 수 있다.
위의 코드에서는 onlyOwner라는 modifier를 사용하여 owner만이 mintNFT라는 함수를 실행시키도록 사용하였다.
📂 Ownable 공식 문서
ERC721에 대한 코드가 완성되었다면, compile 후 deploy를 진행해주면 된다.
Truffle을 사용한다면 truffle-config.js 파일에 배포를 위한 환경설정을 해준다.
설정 및 ganache workspace 추가는 ERC20 배포에서 했던 방식과 동일한 순서로 진행해주면 된다.
환경 설정을 완료했다면 migrations 디렉토리 하위에 delpoy를 위한 js 파일을 작성해준다.
작성하는 migration 파일은 숫자로 시작하는데, 이 숫자에 따라서 각 파일들이 순차적으로 실행되며 한 번 씩만 실행된다.
만일 동일한 파일을 재실행하고 싶을 경우에는 --reset
option을 사용하여 migration 파일을 실행하면 된다.
5_initial_mynft.js 👇
const MyNFT = artifacts.require("MyNFT");
module.exports = function (deployer) {
deployer.deploy(MyNFT);
};
truffle을 이용하여 compile을 하고 migrate를 이용해 배포를 진행해준다.
# code compile
$> npx truffle compile
# code migrate
$> npx truffle migrate
# or
$> npx truffle migrate --reset
배포된 contract는 truffle console에서 실행해볼 수 있다.
truffle console은 npx truffle console
명령어로 열 수 있다.
배포된 contract를 await를 이용해 인스턴스로 생성하고, contract에 작성한 함수들을 실행시켜보면 된다.
# 배포된 contract의 instance 생성
truffle(ganache)> mynft = await MyNFT.deployed()