Klaytn NFT ๊ฐœ๋ฐœ(feat. truffle)

13880 ๋‹จ์–ด githubbaobabKlaytnKIP-17KIP-17

์ฐธ๊ณ >github ๋งํฌ

์ฐธ๊ณ > ๊ณต์‹ klaytn github repository

์‹œ์ž‘ํ•˜๊ธฐ์— ์•ž์„œ

  • ์ค‘๊ฐ„์ค‘๊ฐ„ ๋งํฌ๋ฅผ ๊ฑธ์–ด ๋‘์—ˆ์œผ๋‹ˆ ์ฐธ๊ณ ํ•˜์„ธ์š”.
  • solidity ๋ฌธ๋ฒ•๊ณผ openzeppelin ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ์•ˆ๋‹ค๋Š” ๊ฐ€์ •ํ•˜์— ์ง„ํ–‰๋ฉ๋‹ˆ๋‹ค.
  • ์ž˜๋ชป๋˜๊ฑฐ๋‚˜ ๋ฌธ์˜๊ฐ€ ์žˆ์œผ๋ฉด ๋Œ“๊ธ€ ๋‹ฌ์•„์ฃผ์„ธ์š”.

1. ๋กœ์ปฌ์—์„œ ๊ฐœ๋ฐœ

1-1. ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ & ์„ค์ •

npm install -g truffle@5.1.23
mkdir <project_name>
cd <project_name>
truffle init

1-2. ์ปจํŠธ๋ž™ํŠธ ์ž‘์„ฑ

npm install @klaytn/contracts
  • ์ฃผ์˜) ์œ„ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜๋ฉด klaytn-contracts ํŒŒ์ผ๋“ค์ด ๋‹ค ๋ฐ›์•„์ ธ์•ผ ํ•˜๋‚˜ ์—…๋ฐ์ดํŠธ๋ฅผ ์•ˆํ•œ๊ฑด์ง€ ownership/Ownable.sol ํŒŒ์ผ์ด ์กด์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค. ๋งจ ์œ„์— ์˜ฌ๋ ค๋‘” ๊ณต์‹ klaytn github repository์˜ contract ์ฝ”๋“œ๋กœ ํ†ต์งธ๋กœ ๊ต์ฒดํ•จ. (ownership/Ownable.sol ๋งŒ ์ถ”๊ฐ€ ํ•  ๊ฒฝ์šฐ ๋‹ค๋ฅธ ์ฝ”๋“œ์— ์ ์šฉ ๋˜์–ด ์žˆ๋Š” ๋ถ€๋ถ„๊นŒ์ง€ ์ฐพ์•„์„œ ๋ฐ”๊ฟ”์ค˜์•ผํ•จ)

  • contract ํด๋” ์•ˆ์— ์ž‘์„ฑ

pragma solidity 0.5.6;

import "@klaytn/contracts/token/KIP17/KIP17Full.sol";
import "@klaytn/contracts/drafts/Counters.sol";
import "@klaytn/contracts/ownership/Ownable.sol";

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

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

    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-3. ๋ฐฐํฌ ์Šคํฌ๋ฆฝํŠธ ์ž‘์„ฑ

  • migrations ํด๋”์— 2_initial_mynfts.js ํŒŒ์ผ ์ƒ์„ฑ (๊ทœ์น™ - {์ˆซ์ž}_{์„ค๋ช…}.js)
    ์ฐธ๊ณ >Migrations.sol, 1_initial_migration.js ์€ ์™œ ์žˆ๋Š”์ง€์™€ Migration ํŒŒ์ผ๋ช… ๊ทœ์น™
    - ์š”์•ฝ) migration contract ๋Š” last_completed_migration ์— ๋งˆ์ง€๋ง‰ ๋ฐฐํฌ ์ŠคํŠธ๋ฆฝํŠธ์˜ ๋ฒˆํ˜ธ๋ฅผ ์ €์žฅํ•˜๊ณ  ๋‚˜์ค‘์— ์ปจํŠธ๋ž™ํŠธ๊ฐ€ ์ˆ˜์ •๋˜๊ฑฐ๋‚˜ ์ƒˆ๋กœ์šด ์ปจํŠธ๋ž™ํŠธ๋ฅผ ๋ฐฐํฌํ•  ๋•Œ ๊ธฐ์กด ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ค‘๋ณต ์‹คํ–‰ ํ•˜์ง€ ์•Š๊ธฐ ์œ„ํ•จ. ์ถ”๊ฐ€๋กœ ์ด๋ฏธ ์‹คํ–‰๋œ migration ์„ ์ถ”์ ํ•˜๋Š”๋ฐ ๋„์›€์ด ๋จ.
const MyNFTs = artifacts.require('MyNFTs.sol'); // MyNFTs.sol ํŒŒ์ผ ์ถ”๊ฐ€

module.exports = function(deployer) {
	deployer.deploy(MyNFTs); // MyNFTs๋ฅผ ๋ฐฐํฌ์— ์ถ”๊ฐ€
};

1-4. ganache ๋„คํŠธ์›Œํฌ ์„ค์ •

ganache ์˜ default port๋Š” 7545
ganache-cli ์˜ default port๋Š” 8545

  • klaytn์€ ์ด๋”๋ฆฌ์›€ ๊ธฐ๋ฐ˜์ด๊ธฐ์— ganache ์‚ฌ์šฉ ๊ฐ€๋Šฅ(์ฝ”์ธํ‘œ์‹œ๋Š” ETH๋กœ ํ‘œํ˜„๋จ)
  • truffle project์˜ truffle-config.js ํŒŒ์ผ์—์„œ networks ์˜ต์…˜ ์„ค์ •
    networks: {
        ganache: {				// ์ด๋ฆ„์€ ๊ตฌ๋ณ„ํ•˜๊ธฐ ์‰ฝ๊ฒŒ ์ž‘์„ฑ
         host: "127.0.0.1",
         port: 7545,			// ganache-cli ์— ์—ฐ๊ฒฐํ•œ๋‹ค๋ฉด 8545
         network_id: "*",       // Any network (default: none)
        },
    },

  // Configure your compilers
	compilers: {
		solc: {
			version: "0.5.6",
			settings: {
				evmVersion: "constantinople",
			},
		},
	},

1-5. ์ปจํŠธ๋ž™ํŠธ ๋ฐฐํฌ

  • ganache ๋ฅผ ์‹คํ–‰
	truffle migrate --compile-all --network ganache
  • ๋ชจ๋‘ ์ปดํŒŒ์ผ์„ ํ•˜๊ณ  ganache ๋„คํŠธ์›Œํฌ์— ๋ฐฐํฌํ•œ๋‹ค.
  • ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ์ปดํŒŒ์ผ์„ ๋จผ์ € ํ•œ ํ›„ ganache์˜ ์ฒซ๋ฒˆ์งธ ๊ณ„์ •์œผ๋กœ ๋ฐฐํฌ๋ฅผ ํ•˜๋Š”๋ฐ ์ˆซ์ž ์ˆœ์„œ๋Œ€๋กœ ๋ฐฐํฌ๋ฅผ ์‹œ์ž‘ํ•œ๋‹ค.


    ์ปจํŠธ๋ž™ํŠธ์˜ ์ฃผ์†Œ์™€ ๊ณ„์ •์ •๋ณด, ๊ฐ€์Šค๋น„ ๋“ฑ๋“ฑ ๋‹ค์–‘ํ•œ ์ถœ๋ ฅ์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ๋‹ค.

1-6. ์ปจํŠธ๋ž™ํŠธ ์‹คํ–‰

	truffle console --network ganache
  • MyNFTs.deployed() ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด MyNFTs ์ปจํŠธ๋ž™ํŠธ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค

  • truffle ์ด ๋ฐฐํฌํ•œ MyNFTs ๋ฅผ ์•Œ ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ• (log๋กœ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค) (์ฐธ๊ณ )

  • mintNFT ์— ์ค€๋น„๋œ ๋งํฌ๋ฅผ ์ „๋‹ฌ (์ผ๋ฐ˜์ ์œผ๋กœ NFT๋Š” ๊ทธ๋ฆผํŒŒ์ผ์˜ ๊ฒฝ๋กœ๋ฅผ ๋‹ด์€ metadata์˜ ๊ฒฝ๋กœ๋ฅผ ๋„ฃ์–ด์ค€๋‹ค)
    ์ฐธ๊ณ >OpenSea Metadata ๊ตฌ์กฐ

instance.mintNFT("https://velog.io/@repedore")

  • ์ƒ์†ํ•œ ERC721 contract์˜ tokenURI ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ’ ํ™•์ธํ•˜๊ธฐ(KIP17Metadata.sol : 58 line)
instance.tokenURI(1)
  • ๋„ฃ์€ ๊ฐ’์ด ์ž˜ ์ถœ๋ ฅ๋˜๋Š”๊ฒƒ์„ ํ™•์ธ

2. baobab ํ…Œ์ŠคํŠธ๋„ท์— ๋ฐฐํฌ

2-1. baobab ๋ฐฐํฌ ์„ค์ •

ํ•„์ˆ˜>Truffle๊ณผ Klaytn TestNet ์—ฐ๊ฒฐํ•˜๊ธฐ (feat. baobab)

  • baobab ๋„คํŠธ์›Œํฌ์™€ ์—ฐ๊ฒฐ ํ›„ truffle console ๋กœ ์ง„์ž….
truffle console --network baobab

2-2. baobab ๋ฐฐํฌ

  • migrate ๋ช…๋ น์–ด๋ฅผ ์ž…๋ ฅํ•ด์ฃผ๋ฉด ropsten ํ…Œ์ŠคํŠธ ๋„คํŠธ์›Œํฌ์— ๋ฐฐํฌ๊ฐ€ ์™„๋ฃŒ๋œ๋‹ค
    - migrate ์‹คํ–‰ (์˜จ์ฒด์ธ์ด๋ผ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆผ)

    - MyNFTs ์˜ mintNFT ํ•จ์ˆ˜ ์‹คํ–‰ & ๊ฒฐ๊ณผ ํ™•์ธ

    - ํŠธ๋žœ์žญ์…˜ ํ•ด์‰ฌ๊ฐ’, ์ปจํŠธ๋ž™ํŠธ ์ฃผ์†Œ, ์‹คํ–‰ํ•œ ๊ณ„์ขŒ ์ฃผ์†Œ ๋“ฑ๋“ฑ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

    baobab - Contract ์ฃผ์†Œ
    baobab - TX ์ฃผ์†Œ
  • ๋ฐœํ–‰ํ•œ ๊ณ„์ •์˜ ํ† ํฐ ๋ชฉ๋ก์„ ๋ณด๋ฉด MyNFTs(MNFT)์˜ TokenID ๊ฐ€ 1์ธ ํ† ํฐ์„ ์†Œ์œ ํ•˜๊ณ  ์žˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

2-3. (์ถ”๊ฐ€) OpenSea ์ œ๊ณต Metadata๋กœ NFT ๋งŒ๋“ค๊ธฐ

  • Opensea ์—์„œ klaytn testnet์€ baobab์ด๋ผ ์ปจํŠธ๋ž™ํŠธ๋ฅผ ๋ฐ”๋กœ ์‚ฌ์šฉํ•ด์„œ mint๋งŒ ํ•ด์ฃผ๋ฉด ๋จ
  • ๋ฐœํ–‰ํ•œ ์ปจํŠธ๋ž™ํŠธ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
	instance = await MyNFTs.deployed()
    instance.name()			// ์ž˜ ๋ถˆ๋Ÿฌ์™”๋‚˜ ํ™•์ธ
	instance.mintNFT('https://opensea-creatures-api.herokuapp.com/api/creature/3')


OpenSea ํ™•์ธ
baobab - Contract ์ฃผ์†Œ(์œ„์™€ ๋™์ผ)
baobab - TX ์ฃผ์†Œ

ํšŒ๊ณ 

Klaytn ์ด Ethereum ๊ธฐ๋ฐ˜์ด๋ผ ๋งŽ์€ ๋ถ€๋ถ„์ด ๋น„์Šทํ•˜์—ฌ ์ง„ํ–‰์„ ์ˆ˜์›”ํ•˜๊ฒŒ ํ–ˆ๋‹ค.
klaytn ๋ถ€๋ถ„์„ ์ •๋ฆฌํ•˜๋ฉด์„œ Ethereum ๋ฐฉ์‹์œผ๋กœ ๋ฐ˜๋ณตํ•˜๋‹ค๋ณด๋‹ˆ truffle ์— ๋” ์ต์ˆ™ํ•ด์ง„๊ฒƒ ๊ฐ™๋‹ค.
์‚ฌ์‹ค ๋‹ค ํ•˜๊ณ  ๋‚˜์„œ ์ƒ๊ฐํ•ด๋ณด๋ฉด ๋น„์Šทํ•œ๊ฒŒ ์•„๋‹ˆ๋ผ ๋ชจ๋“ ๊ฒŒ ๊ฐ™์•˜๋‹ค.
๊ทผ๋ฐ ๋‚œ ์ด๋ ‡๊ฒŒ ๋ธ”๋กœ๊น…์œผ๋กœ ์ •๋ฆฌ ํ•˜๊ธฐ ์ „๊นŒ์ง€ ์™„๋ฒฝํ•˜๊ฒŒ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ํ•  ์ˆ˜ ์žˆ์„๊ฑฐ๋ผ๊ณ  ์ƒ๊ฐ์„ ๋ชปํ–ˆ๋‹ค.
์•„๋งˆ ๊ฒฝํ—˜์ด๋ž‘ ๊ฐœ๋…์ด ๋ถ€์กฑํ•ด์„œ ๊ทธ๋Ÿฐ๊ฒƒ ๊ฐ™๋‹ค.
๊ทธ๋ž˜๋„ ์ž‘์€ ๊ธฐ์ค€์„ ์„ธ์› ์œผ๋‹ˆ ์ด๊ฑธ ๋ฐ”ํƒ•์œผ๋กœ ๋” ๋งŽ์€ ํ™•์žฅ์„ ์ด๋ค„๋‚ด๋ณด์ž.

PS)์•„.. klaytn contract code verify ๋Š” ๊ตฌ๊ธ€ ํผ์œผ๋กœ ๋ฐ›๋Š”๊ฒƒ ๊ฐ™์€๋ฐ....... ์™œ์ด๋ ‡๊ฒŒ ํ•˜๋Š”๊ฑด์ง€๋Š” ์ž˜ ๋ชจ๋ฅด๊ฒ ์ง€๋งŒ... ๊ทธ๋ž˜๋„ ํ•˜๋Š”๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ด์•ผ ํ•  ๊ฒƒ ๊ฐ™๋‹ค.

์ข‹์€ ์›นํŽ˜์ด์ง€ ์ฆ๊ฒจ์ฐพ๊ธฐ