---
# System prepended metadata

title: 從以太坊白皮書理解 web 3 概念 - Day24
tags: [' Web 3', it 鐵人賽 30 天, ' ethereum']

---

---
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 資訊
![](https://i.imgur.com/fvjCi7w.png)

這時候打開另一個 terminal 使用以下指令發佈 NFTMinter Contract 到鏈上
```shell=
yarn deploy
```

然後就會看到以下畫面

![](https://i.imgur.com/ks4kW0Q.png)

接著可以執行以下指令來執行 Dapp

```shell=
yarn start
```
透過執行 mint 動作
![](https://i.imgur.com/VRAdJnI.png)
讀取 mint 完的 id
![](https://i.imgur.com/6zx5Ir1.png)

## 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 並且把內容讀取出來

