---
tags: it 鐵人賽 30 天, Web 3, ethereum
---
# 從以太坊白皮書理解 web 3 概念 - Day24
## NFT School Day 2 - 建立鑄造 NFT 的系統 - 透過 IPFS 與 Smart Contract
今天會透過 [minting system](https://nftschool.dev/tutorial/minting-service/) 學習透過 IPFS 與 Smart Contract 實作一個鑄造 NFT 的系統
所謂的鑄造就是建立一個 NFT,除了需要透過 Smart Contract 設定唯一識別代號並且需要設定一個該 token 所對應的實體物件 URI 。
為了方便實作這邊把實際物件設定為數位圖片,並且把數位圖片放到 ipfs 之上產生 hash 做識別號
把這個識別號設定為 NFT 的 URI
## 什麼是 IPFS?為何使用 IPFS?
IPFS 是一種分散式存儲系統技術,對每個存入的檔案內容產生唯一識別代號,特別的是這個識別帶會是根據檔案內容所產生出來的。
所以可以避免檔案被更換而 NFT 持有者卻不知道
這邊範例採用 [nft.storage](https://nft.storage/) 這個專門放 NFT 數位資產的一個存儲服務是建構在 IPFS 之上的服務
## 建構 IPFS 與 SMART Contract
這邊會採用 [scaffold-eth](https://github.com/scaffold-eth/scaffold-eth) 這個 Dapp 專案當作基底來建構 minting service
透過以下指令 clone 專案
```shell=
git clone https://github.com/ipfs-shipyard/nft-school-examples
cd nft-school-examples/end-to-end
```
安裝所需套件
```shell=
yarn install
```
使用以下指定在 local 模擬
```shell=
yarn chain
```
這個指令執行之後為顯示以下這些 account 資訊

這時候打開另一個 terminal 使用以下指令發佈 NFTMinter Contract 到鏈上
```shell=
yarn deploy
```
然後就會看到以下畫面

接著可以執行以下指令來執行 Dapp
```shell=
yarn start
```
透過執行 mint 動作

讀取 mint 完的 id

## minting 是如何運作的?
這邊是透過 NFTMinter Smart Contract 來建立 NFT Token
NFTMinter Contract 如下
```solidity=
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import "hardhat/console.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
contract NFTMinter is ERC721 {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
constructor(string memory tokenName, string memory symbol) ERC721(tokenName, symbol) {
_setBaseURI("ipfs://");
}
function mintToken(address owner, string memory metadataURI)
public
returns (uint256)
{
_tokenIds.increment();
uint256 id = _tokenIds.current();
_safeMint(owner, id);
_setTokenURI(id, metadataURI);
return id;
}
}
```
可以注意到這邊只需要紀錄 nft.storage 所產生 uri 到對應的 token id
所以每次鑄造都會產生一個唯一識別代號 tokenId 並且把 nft.storage 所產生的 uri 儲存下來
### 1. 把圖片上傳 nft.storage
語法如下:
```javascript=
const client = new NFTStorage({ token: NFT_STORAGE_KEY });
const metadata = await client.store({
name,
description,
image,
});
```
### 2. 呼叫 mintToken 功能
```javascript=
// our smart contract already prefixes URIs with "ipfs://", so we remove it before calling the `mintToken` function
const metadataURI = metadata.url.href.replace(/^ipfs:\/\//, "");
// scaffold-eth's Transactor helper gives us a nice UI popup when a transaction is sent
const transactor = Transactor(provider, gasPrice);
const tx = await transactor(contract.mintToken(ownerAddress, metadataURI));
setStatus("Blockchain transaction sent, waiting confirmation...");
// Wait for the transaction to be confirmed, then get the token ID out of the emitted Transfer event.
const receipt = await tx.wait();
let tokenId = null;
for (const event of receipt.events) {
if (event.event !== 'Transfer') {
continue
}
tokenId = event.args.tokenId.toString();
break;
}
```
## 結語
這個 Dapp 實踐了鑄造 NFTToken 並且把內容讀取出來