# 如何在 Polygon 鏈上鑄造 NFT * [ mint-nftstorege-polygon](https://nftschool.dev/tutorial/mint-nftstorage-polygon/) * 參考自[從以太坊白皮書理解 web 3 概念](https://ithelp.ithome.com.tw/m/articles/10306796) 有以下3特性: 1. 可拓展性:避免過高鑄造花費、過慢鑄造速度 2. 持久性:在 NFT BURN 之前,asset 資料能一直存在 3. 不可修改性: NFT 與其對應的數位資產避免被串改 <blockquote> Polygon 鏈強調於其可拓展性。並且相容於 Ethereum 與 EVM。 nft.storage 則保證其持久性透過 Filecoin 網路,透過 IPFS 保證其不可修改性。 </blockquote> ### 環境設定 * nodejs:16.14.0 * npm:版本8.0.0 ↑ 其他設定 1. MetaMask 錢包安裝 2. 設定 MetaMask 連接網路到 [Polygon Mumbai 測試鏈](https://blog.pods.finance/guide-connecting-mumbai-testnet-to-your-metamask-87978071aca8) 3. 透過 [Mumbai faucet](https://faucet.polygon.technology/) 取得 MATIC token 4. 複製 MetaMask 錢包製作出來 Private Key: 需要來產生簽章 ### 準備 [取得 nft.storage 的 API KEY](https://nft.storage/login/) ### 設定 node module 執行環境 * Hardhat、Hardhat-Ethers、ethers: 用來開發 Ethereum 的開發執行環境其中相容於 Polygon * OpenZeppelin: 用來開發 Smart Contract 的函式庫 * nft.storage: 用來連接 nft.storage api * dotenv: 用來讀取環境變數 建立資料夾 polygon_nft_mint ```csharp! mkdir polygon_nft_mint ``` 初始化 node_module 環境 ```csharp! cd polygon_nft_mint npm init -y ``` 安裝所需套件 ```csharp! npm add hardhat @openzeppelin/contracts nft.storage dotenv @nomiclabs/hardhat-ethers ethers@^5.0.0 ``` 執行 hardhat 初始化 ```csharp! npx hardhat ``` 選擇 Create an empty hardhat.config.js 並更新 hardhat.config.js: ```javascript! /** * @type import('hardhat/config').HardhatUserConfig */ require("@nomiclabs/hardhat-ethers"); require('dotenv').config(); const { PRIVATE_KEY } = process.env; module.exports = { defaultNetwork: "PolygonMumbai", networks: { hardhat: { }, PolygonMumbai: { url: "https://rpc-mumbai.maticvigil.com", accounts: [PRIVATE_KEY] } }, solidity: { version: "0.8.12", settings: { optimizer: { enabled: true, runs: 200 } } }, } ``` 建立一個 .env 檔案: ```env! PRIVATE_KEY="wallet private key" NFT_STORAGE_API_KEY="Your api key" ``` 下一步建立三個資料夾 1. contracts: 用來存放 Smart Contract 2. assets: 用來存放要放到 nft.storage 的數位資料 3. scripts: 用來存放要執行發佈的 javascript 檔案 ```csharp! mkdir contracts assets scripts ``` ### 鑄造 NFT 把數位檔案放到 nft.storage 建立scripts/store-asset.mjs 把要用的圖片放到assets ```ECMAScript! import { NFTStorage, File } from "nft.storage" import fs from 'fs' import dotenv from 'dotenv' dotenv.config() const API_KEY = process.env.NFT_STORAGE_API_KEY async function storeAsset() { const client = new NFTStorage({ token: API_KEY }) const metadata = await client.store({ name: 'Little Red Riding Hood_NFT', description: 'This famous tale is short but very SNAPPY!', image: new File( [await fs.promises.readFile('assets/Little Red Riding Hood.jpg')], 'pig.jpg', { type: 'image/jpg' } ), external_url: new File( [await fs.promises.readFile('assets/Little Red Riding Hood.pdf')], 'pig.pdf', { type: 'application/pdf' } ), attributes: [ { "trait_type": "other_trading_sites", "value": "https://shp.ee/quwxcgm" }, { "trait_type": "seller_email", "value": "example@gmail.com" }, { "trait_type": "seller_phone", "value": "0927XXXX76" } ] }) console.log("Metadata stored on Filecoin and IPFS with URL:", metadata.url) } storeAsset() .then(() => process.exit(0)) .catch((error) => { console.error(error); process.exit(1); }); ``` 透過執行以下指令就可以把檔案上傳並且產生 meta 資料 `node scripts/store-asset.mjs` ![](https://i.imgur.com/sLtdBuY.png) ### 在 Polygon 建立 NFT 建立 Smart Contract 來做鑄造 建立 contracts/ExampleNFT.sol ```solidity! // SPDX-License-Identifier: MIT pragma solidity ^0.8.12; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; import "@openzeppelin/contracts/utils/Counters.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; contract ExampleNFT is ERC721URIStorage, Ownable { using Counters for Counters.Counter; Counters.Counter private _tokenIds; constructor() ERC721("NFT", "ENFT") {} 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; } } ``` <blockquote> @openzeppelin/contracts/token/ERC721/ERC721.sol 包含了所有 ERC-721 標準,實作了關於 NFT Token 所需要的特性 @openzeppelin/contracts/utils/Counters.sol 替供了一個 Counter 可以隨著呼叫 increment() 來不斷增加,這邊用來當作 unqiue ID @openzeppelin/contracts/access/Ownable.sol 用來設定 NFT 的存取權限 constructor 這邊用來把 ERC-721 特性附加到 NFT 上面 可以看到 mintNFT 這個 function 的存取權限是 onlyOwner 代表只有 Smart Contract 的 onwer 才能呼叫 mintNFT 的第一個參數 recipient 是用來設定 NFT 接收者的 address mintNFT 的第二個參數 tokenURI 則是用來儲存一個能夠顯示 NFT metadata 的 URL </blockquote> ### 發佈 Smart Contract 到 Polygon 鏈 建立 scripts/deploy-contract.mjs ```ECMAScript! async function deployContract() { const ExampleNFT = await ethers.getContractFactory("ExampleNFT") const exampleNFT = await ExampleNFT.deploy() await exampleNFT.deployed() // This solves the bug in Mumbai network where the contract address is not the real one const txHash = exampleNFT.deployTransaction.hash const txReceipt = await ethers.provider.waitForTransaction(txHash) const contractAddress = txReceipt.contractAddress console.log("Contract deployed to address:", contractAddress) } deployContract() .then(() => process.exit(0)) .catch((error) => { console.error(error); process.exit(1); }); ``` 以下指令部署 `npx hardhat run scripts/deploy-contract.mjs --network PolygonMumbai` ![](https://i.imgur.com/LwPBGO7.png) ### 鑄造 NFT 到 Polygon 利用得到的metadata URL、合約部署位址 建立scripts/mint-nft.mjs ```ECMAScript! const CONTRACT_ADDRESS = "0xA16871aC60308AB87Ce1DBdF93644456FF7D3BE6" const META_DATA_URL = "ipfs://bafyreibcgwqmp6fzter7zebelf57ae3hktkqaejbwatl4ka4li4qbspbwi/metadata.json" async function mintNFT(contractAddress, metaDataURL) { const ExampleNFT = await ethers.getContractFactory("ExampleNFT") const [owner] = await ethers.getSigners() await ExampleNFT.attach(contractAddress).mintNFT(owner.address, metaDataURL) console.log("NFT minted to: ", owner.address) } mintNFT(CONTRACT_ADDRESS, META_DATA_URL) .then(() => process.exit(0)) .catch((error) => { console.error(error); process.exit(1); }); ``` 指令鑄造 `npx hardhat run scripts/mint-nft.mjs --network PolygonMumbai` ![](https://i.imgur.com/v0rfi1O.png) 可以到[opensea](https://testnets.opensea.io/account/created)看鑄造出來的NFT ![](https://i.imgur.com/RTul9xs.png) <!-- ![](https://i.imgur.com/ouuJ52U.png) -->