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
❯ mkdir ha-ntf-truffle
❯ cd ha-ntf-truffle/
❯ npm init
❯ truffle init
❯ npm i --save truffle-hdwallet-provider
❯ npm i dotenv
// 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"
}
}
},
// 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
}
}
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;
}
}
❯ npm i @openzeppelin/contracts
added 1 package, and audited 2 packages in 643ms
found 0 vulnerabilities
//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);
};
.env
파일을 생성하여 Metamask mnemonic과 infura ropsten endpoint를 작성한다.//.env
MNEMONIC=
INFURA_ENDPOINT=
❯ 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
❯ truffle console --network ropsten
truffle(ropsten)>
truffle(ropsten)> instance = await NewNFT.deployed()
undefined
truffle(ropsten)> instance.name()
'HJ NFT'
truffle(ropsten)> instance.symbol()
'HJN'
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"
}
]
}
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]
}
]
}
tokenURI
를 확인한다.truffle(ropsten)> instance.tokenURI(1)
'/Users/yuhaejeong/Workspace/git/ha-ntf-truffle/test.json'
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/