前言 本文為「Alchemy - How to Create an NFT Tutorial 」教學的學習筆記。
建立專案 建立專案。
1 2 mkdir eth-nft-examplecd eth-nft-example
建立 package.json
檔。
安裝 hardhat
依賴套件。
1 npm install hardhat --save-dev
使用 Hardhat 初始化專案。
檢查專案配置是否正常。
合約實作 安裝依賴。
1 npm install @openzeppelin/contracts
刪除 contracts/Lock.sol
範例檔。
新增 contracts/MyNFT.sol
檔。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; import "@openzeppelin/contracts/utils/Counters.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; contract MyNFT is ERC721URIStorage, Ownable { using Counters for Counters.Counter; Counters.Counter private _tokenIds; constructor() ERC721("MyNFT", "NFT") {} 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; } }
部署合約 安裝依賴套件。
1 npm install dotenv --save
建立 .env
檔。
1 2 3 API_URL=https://eth-goerli.alchemyapi.io/v2/your-api-key API_KEY=your-api-key PRIVATE_KEY=your-metamask-private-key
更新 hardhat.config.js
檔。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 require ('dotenv' ).config ();require ("@nomiclabs/hardhat-ethers" );const { API_URL , PRIVATE_KEY } = process.env ;module .exports = { solidity : "0.8.4" , defaultNetwork : "goerli" , networks : { hardhat : {}, goerli : { url : API_URL , accounts : [`0x${PRIVATE_KEY} ` ], }, }, };
修改 scripts/deploy.js
檔。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 async function main ( ) { const MyNFT = await ethers.getContractFactory ("MyNFT" ); const myNFT = await MyNFT .deploy (); console .log ("Contract deployed to address:" , myNFT.address ); } main () .then (() => process.exit (0 )) .catch (error => { console .error (error); process.exit (1 ); });
執行部署。
1 npx hardhat run scripts/deploy.js --network goerli
輸出訊息如下。
1 Contract deployed to address: 0xAdEc9c114D4E094545E60E2e856Ab57552831c00
設定 NFT 到 Pinata 註冊帳號,此服務能夠將圖片上傳到 IPFS 星際檔案系統。
註冊後,上傳一張圖片,將圖片的 CID 複製起來。
建立一個 nft-metadata.json
檔,做為 NFT 的描述檔,並修改 image
欄位,將其設置為圖片的 URI。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 { "attributes" : [ { "trait_type" : "Breed" , "value" : "Maltipoo" } , { "trait_type" : "Eye color" , "value" : "Mocha" } ] , "description" : "The world's most adorable and sensitive pup." , "image" : "https://gateway.pinata.cloud/ipfs/QmWCoZdz2tnv38dqWSD1Yd2sf41R1CHWpogkVpLaNoa3C9" , "name" : "My First NFT" }
最後,上傳 nft-metadata.json
檔,並將 NFT 的描述檔的 CID 複製起來。
鑄造 NFT 建立 src/mint.js
檔,將 tokenURI
變數設定為 NFT 的描述檔的 URI。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 require ("dotenv" ).config ();const ethers = require ("ethers" );const { abi } = require ("../artifacts/contracts/MyNFT.sol/MyNFT.json" );const { API_KEY , PRIVATE_KEY } = process.env ;const provider = new ethers.providers .AlchemyProvider ("goerli" , API_KEY );const signer = new ethers.Wallet (PRIVATE_KEY , provider);const contractAddress = "0xAdEc9c114D4E094545E60E2e856Ab57552831c00" ;const myNftContract = new ethers.Contract (contractAddress, abi, signer);const tokenURI = "https://gateway.pinata.cloud/ipfs/QmPkfQpZAARb4ZoQVHyLfktvLS6x8WJ9w2yp1XRrZuEeqU" ;const mintNFT = async ( ) => { let nftTxn = await myNftContract.mintNFT (signer.address , tokenURI); await nftTxn.wait (); console .log (`NFT Minted! Check it out at: https://goerli.etherscan.io/tx/${nftTxn.hash} ` ); }; mintNFT () .then (() => process.exit (0 )) .catch ((error ) => { console .error (error); process.exit (1 ); });
執行鑄造腳本。
輸出訊息如下。
1 NFT Minted! Check it out at: https://goerli.etherscan.io/tx/0xbba6d2d835fbe58dde91d04676b04a85a5bbf088e78bee7c6166a1155769f58a
程式碼
參考資料