今天將會透過 mint-nftstorege-polygon 來學習如何透過透過 nft.storage service 在 Polygon 鏈上鑄造 NFT
為了以下3個特性
所以選用了 Polygon 鏈與 nft.storage 這個 IPFS servcie
Polygon 鏈強調於其可拓展性。並且相容於 Ethereum 與 EVM。
nft.storage 則保證其持久性透過 Filecoin 網路,透過 IPFS 保證其不可修改性
為了能夠方便測試與運行 Smart Contract
需要先安裝 nodejs 到 16.14.0 與 npm 需要在版本 8.0.0 以上
其他設定
透過 nft.storage 網址 登入
並且透過設定產生一把 API KEY
這把 API KEY 是用來使用 storage api 所需要的
建立資料夾 polygon_nft_mint
mkdir polygon_nft_mint
初始化 node_module 環境
yarn init -y
安裝所需套件
yarn add hardhat @openzeppelin/contracts nft.storage dotenv @nomiclabs/hardhat-ethers ethers@^5.0.0
執行 hardhat 初始化
npx hardhat
選擇 Create an empty hardhat.config.js
✔ What do you want to do? · Create an empty hardhat.config.js
✨ Config file created ✨
然後更新 hardhat.config.js 如下
/**
* @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 檔案 內容如下
PRIVATE_KEY="wallet private key"
NFT_STORAGE_API_KEY="Your api key"
接下來分別建立3個資料
建立指令如下:
mkdir contracts assets scripts
建立一個 scripts/store-asset.mjs 內容如下
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: 'ShadowWarriorNFT',
description: 'shadow warrior is an awesome artwork!',
image: new File(
[await fs.promises.readFile('assets/shadow.png')],
'shadow.png',
{ type: 'image/png' }
),
})
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
建立 contracts/ExampleNFT.sol 如下
// 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;
}
}
在最上面引用了 4 個 Contract
@openzeppelin/contracts/token/ERC721/ERC721.sol 包含了所有 ERC-721 標準實作了關於 NFT Token 所需要的特性
@openzeppelin/contracts/utils/Counters.sol 替供了一個 Counter 類似於資料庫 Serial 一樣可以做到隨則呼叫 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
建立 scripts/deploy-contract.mjs 如下
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
接著利用剛剛的那兩個資訊
來撰寫 scripts/mint-nft.mjs
const CONTRACT_ADDRESS = "0x12b8FE2671325258c251C926918B162D2c822b46"
const META_DATA_URL = "ipfs://bafyreihqlqporf35mkbjul6453hqsocbqstb4uawql5laebjjybxhfflhe/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
然後就可以透過 openset 平台來察看已鑄造的 NFT
比如本文所鑄造NFT 如下
https://testnets.opensea.io/assets/mumbai/0x12b8fe2671325258c251c926918b162d2c822b46/1