---
title: "如何建立 NFT"
description: "逐步教學,說明如何使用 Metamask、Solidity、Hardhat、Pinata 與 Alchemy,在 Ethereum 區塊鏈上建立並部署你自己的 NFT。"
---

# 如何建立 NFT

本教學將帶你使用 Ethereum 和 Inter Planetary File System（IPFS）撰寫並部署一個非同質化（ERC721）代幣智慧合約。

_預估完成時間：約 15 分鐘_

即使你完全不關心這個領域，應該也已經注意到各大新聞媒體都在報導 NFT 的興起。

隨著 NFT 讓區塊鏈進入大眾視野，現在正是自己動手發布 NFT（ERC-721 代幣）到 Ethereum 區塊鏈上、親身理解這股熱潮的好機會！

在本教學中，我們會使用 [Metamask](https://metamask.io/)、[Solidity](https://docs.soliditylang.org/en/v0.8.0/)、[Hardhat](https://hardhat.org/)、[Pinata](https://pinata.cloud/) 和 [Alchemy](https://alchemy.com/?r=affiliate:68212b46-a5c5-4f4c-bc8b-73f50536fcaf)，在 Sepolia 測試網路上建立並部署一個 ERC-721 智慧合約（如果你現在還不了解這些名詞的意思也沒關係，我們會解釋）。在本教學的第二部分，我們會說明如何用智慧合約[鑄造一個 NFT](/blog/how-to-mint-an-nft-using-web3-js)，第三部分則會說明如何[在 Metamask 上查看你的 NFT](/blog/how-to-view-your-nft-in-your-mobile-wallet)。

當然，如果你在任何階段有疑問，歡迎造訪 [Alchemy 支援中心](https://www.alchemy.com/support)！

## 步驟 1：連接到 Ethereum 網路

向 Ethereum 區塊鏈發送請求的方法有很多種，但為了簡化流程，我們會使用 [Alchemy](https://alchemy.com/?r=affiliate:68212b46-a5c5-4f4c-bc8b-73f50536fcaf) 的免費帳號——這是一個區塊鏈開發者平台兼 API，讓我們不需要自行運行節點就能與 Ethereum 鏈通訊。

在本教學中，我們也會運用 Alchemy 的開發者工具進行監控與分析，了解智慧合約部署背後實際發生的事情。如果你還沒有 Alchemy 帳號，可以[在這裡](https://alchemy.com/?r=affiliate:68212b46-a5c5-4f4c-bc8b-73f50536fcaf)免費註冊。

## 步驟 2：建立你的 App（以及 API key）

建立 Alchemy 帳號後，你可以透過建立一個 App 來產生 API key。這樣我們就能向 Sepolia 測試網路發送請求。如果你想更了解測試網路，可以參考[這篇指南](https://www.alchemy.com/docs/choosing-a-web3-network)。

1. 將滑鼠移到導覽列的「Apps」上，點選「Create App」，進入 Alchemy Dashboard 的「Create App」頁面

<ImageBlock
  src="https://media.alchemy.com/1704631152-create-a-new-app.jpg"
  alt="Alchemy 儀表板：從 Apps 選單建立新的 app"
  width={2880}
  height={1640}
  caption="建立新的 app"
/>

2. 為你的 App 命名（我們取名為「My First NFT!」），填寫簡短說明，Environment 選擇「Staging」（用於你的 App 記錄管理），Network 選擇「Sepolia」。

<ImageBlock
  src="https://media.alchemy.com/1704802198-name-your-app.png"
  alt="舊版 Alchemy 儀表板的 app 建立畫面，含測試網路選擇器"
  width={1518}
  height={912}
  caption="為你的 app 命名並輸入描述"
/>

3. 點選「Create app」就完成了！你的 App 應該會出現在下方的表格中。

## 步驟 3：建立一個 Ethereum 帳號（地址）

我們需要一個 Ethereum 帳號來發送與接收交易。在本教學中，我們會使用 Metamask——一個瀏覽器中的虛擬錢包，用來管理你的 Ethereum 帳號地址。如果你想更了解 Ethereum 上的交易如何運作，可以查看 Ethereum 基金會的[這個頁面](https://ethereum.org/en/developers/docs/transactions/)。

你可以[在這裡](https://metamask.io/download.html)免費下載並建立一個 Metamask 帳號。在建立帳號時，或如果你已經有帳號，請務必切換到 Sepolia 測試網路（這樣我們就不會動用到真的錢）。

<ImageBlock
  src="https://media.alchemy.com/1704802303-download-and-create-a-metamask-account.png"
  alt="舊版 MetaMask 錢包設定畫面，含測試網路選擇器"
  width={712}
  height={1194}
  caption="下載並建立 Metamask 帳號"
/>

## 步驟 4：從水龍頭取得 ether

為了將智慧合約部署到測試網路，我們需要一些假的 Eth。要取得 Eth，你可以前往 [Sepolia faucet](/faucets/ethereum-sepolia)，輸入你的 Sepolia 帳號地址，並請求 Sepolia Eth。不久之後，你應該就能在 Metamask 帳號中看到 Eth！

## 步驟 5：檢查你的餘額

為了雙重確認餘額確實入帳，讓我們使用 [Alchemy 的 composer 工具](https://www.alchemy.com/composer/?composer_state=%7B%22network%22%3A0%2C%22methodName%22%3A%22eth_getBalance%22%2C%22paramValues%22%3A%5B%22%22%2C%22latest%22%5D%7D)發送一個 `eth_getBalance` 請求。這會回傳我們錢包中的 Eth 數量。輸入你的 Metamask 帳號地址並點選「Send Request」後，你應該會看到類似這樣的回應：

\{"jsonrpc": "2.0", "id": 0, "result": "0xde0b6b3a7640000"\}

**注意：** 這個結果單位是 wei，不是 eth。wei 是 ether 最小的計價單位。wei 換算成 eth 的公式是：1 eth = 10¹⁸ wei。所以如果我們把 0xde0b6b3a7640000 轉換成十進位，會得到 1*10¹⁸，也就是 1 eth。

太好了！我們的假錢都到位了！🤑

## 步驟 6：初始化我們的專案

首先，我們需要為專案建立一個資料夾。打開你的[命令列](https://www.computerhope.com/jargon/c/commandi.htm)並輸入：

進入專案資料夾後，我們會用 npm init 來初始化專案。如果你還沒安裝 npm，請依照[這些說明](https://nodejs.org/en/download/)安裝（我們也會需要 [Node.js](https://nodejs.org/en/download/)，所以也一併下載吧！）。

安裝過程中的問題怎麼回答其實都無所謂，以下是我們的回答方式供你參考：

確認 package.json 後，就完成了！

步驟 7：下載 [Hardhat](https://hardhat.org/getting-started/#overview)

Hardhat 是一個用來編譯、部署、測試和除錯你的 Ethereum 軟體的開發環境。它能幫助開發者在正式上鏈之前，先在本機建置智慧合約與[應用程式](https://www.alchemy.com/dapps/top/defi-dapps)。

打開終端機，確認你在 my-nft 專案資料夾內，然後執行：

想了解更多安裝細節，可以查看[這個頁面](https://hardhat.org/getting-started/#overview)。

## 步驟 8：建立 Hardhat 專案

在我們的專案資料夾內執行：

接著你會看到歡迎訊息，並被要求選擇要做的事。選擇「create an empty hardhat.config.js」：

這會為我們產生一個 **hardhat.config.js** 檔案，這裡就是我們用來設定整個專案的地方（在步驟 13 會用到）。

## 步驟 9：新增專案資料夾

為了讓專案結構清楚，我們會建立兩個新資料夾。在命令列中導覽到專案的根目錄，然後輸入：

**contracts/** 用來存放我們的 NFT 智慧合約程式碼

scripts/ 用來存放部署與操作智慧合約的腳本

## 步驟 10：撰寫我們的合約

環境設定好了，接下來要進入更有趣的部分：撰寫智慧合約程式碼！

用你喜歡的編輯器（我們喜歡用 [VSCode](https://code.visualstudio.com)）打開 my-nft 專案。智慧合約是用一種叫做 [Solidity](https://www.alchemy.com/overviews/solidity) 的語言撰寫，我們也會用它來撰寫 MyNFT.sol 智慧合約。

1. 到「contracts」資料夾，建立一個新檔案叫 MyNFT.sol

2. 以下是我們的 NFT 智慧合約程式碼，基於 [OpenZeppelin](https://docs.openzeppelin.com/contracts/3.x/erc721) 函式庫的 ERC721 實作。將以下內容複製貼上到你的 MyNFT.sol 檔案中。

<CalloutBlock>

注意：如果你想透過智慧合約為 NFT 訂定價格，可以參考[這篇教學](https://www.alchemy.com/docs/reference/nft-api-endpoints)。

</CalloutBlock>

1. 因為我們繼承了 OpenZepplin 合約函式庫的類別，請在命令列執行以下指令，將該函式庫安裝到我們的資料夾中：

**textnpm install @openzeppelin/contracts@3.1.0-solc-0.7**

那麼，這段程式碼到底做了什麼？我們逐行來分析。

在第 5-7 行，我們的程式碼繼承了三個 [OpenZepplin](https://openzeppelin.com) 智慧合約類別：

- @[openzeppelin](https://www.alchemy.com/dapps/openzeppelin)/contracts/token/ERC721/ERC721.sol 包含 ERC721 標準的實作，我們的 NFT 智慧合約會繼承這個實作。（要成為有效的 NFT，你的智慧合約必須實作 ERC721 標準的所有方法。）想了解更多繼承來的 ERC721 函式，可以查看[這裡](https://eips.ethereum.org/EIPS/eip-721)的介面定義。

- @openzeppelin/contracts/utils/Counters.sol 提供只能以 1 為單位遞增或遞減的計數器。我們的智慧合約使用計數器來追蹤已鑄造的 NFT 總數，並將唯一 ID 設定給我們的新 NFT。每個用智慧合約鑄造的 NFT 都必須被分配一個唯一的 ID——這裡的唯一 ID 就是由目前已存在的 NFT 總數決定。舉例來說，我們用智慧合約鑄造的第一個 NFT ID 為「1」，第二個 NFT ID 為「2」，依此類推。

- @openzeppelin/contracts/access/Ownable.sol 為我們的智慧合約設定[存取控制](https://docs.openzeppelin.com/contracts/3.x/access-control)，讓只有智慧合約的擁有者（也就是你）能夠鑄造 NFT。請注意，是否加入存取控制純粹是個人偏好。如果你希望任何人都能用你的智慧合約鑄造 NFT，可以移除第 10 行的 Ownable 以及第 17 行的 onlyOwner。

在第 10-28 行，是我們自訂的 NFT 智慧合約，內容出乎意料地短——只包含一個計數器、一個建構子，以及單一一個函式！這都要歸功於我們繼承的 OpenZepplin 合約，它們已經實作了建立 NFT 所需的大部分方法，例如 ownerOf（回傳 NFT 的擁有者）和 transferFrom（轉移 NFT 的所有權）。

在第 14 行，你會注意到我們將兩個字串「MyNFT」和「NFT」傳入 ERC721 的建構子。第一個變數是智慧合約的名稱，第二個是它的符號。這兩個變數你都可以自由命名！

最後，從第 16 行開始，是我們的函式 mintNFT()，它讓我們能夠鑄造一個 NFT！你會注意到這個函式接收兩個變數：

- address recipient 指定將收到你剛鑄造的 NFT 的地址

- string memory tokenURI 是一個字串，應該指向一份描述 NFT 中繼資料（metadata）的 JSON 文件。NFT 的中繼資料才是真正賦予它生命力的部分，讓它能擁有額外的屬性，例如名稱、描述、圖片和其他特性。在本教學的第二部分，我們會說明如何設定這個中繼資料。

**mintNFT** 呼叫了一些繼承自 ERC721 函式庫的方法，最終回傳一個代表剛鑄造 NFT ID 的數字。

## 步驟 11：將 MetaMask 和 Alchemy 連接到你的專案

現在我們已經建立了 Metamask 錢包、Alchemy 帳號，也寫好了智慧合約，是時候把這三者連接起來了。

從你的虛擬錢包發出的每一筆交易，都需要用你獨一無二的私鑰進行簽名。為了讓我們的程式取得這個授權，我們可以將私鑰（以及 Alchemy API key）安全地存放在一個環境變數檔案中。

想了解更多發送交易的細節，可以查看[這篇教學](https://docs.alchemy.com/docs/how-to-send-transactions-on-ethereum)，內容是關於用 web3 發送交易。

首先，在你的專案目錄中安裝 dotenv 套件：

接著，在專案的根目錄建立一個 **.env** 檔案，並在裡面加入你的 Metamask 私鑰和 HTTP Alchemy API URL。

注意：你的 .env 檔案名稱必須是 .env！請不要改成 xx.env 之類的名稱

- 依照[這些說明](https://metamask.zendesk.com/hc/en-us/articles/360015289632-How-to-Export-an-Account-Private-Key)匯出你在 Metamask 的私鑰

- 請參考下方取得 HTTP Alchemy API URL 並複製到剪貼簿

<ImageBlock
  src="https://media.alchemy.com/1704631290-copy-your-alchemy-api-key.gif"
  alt="Alchemy 儀表板：複製 app 的 HTTP API URL 供 .env 檔案使用"
  width={843}
  height={480}
  caption="複製你的 Alchemy API key"
/>

你的 **.env** 應該會像這樣：

## 步驟 12：安裝 Ethers.js

Ethers.js 是一個函式庫，它將[標準的 JSON-RPC 方法](https://www.alchemy.com/docs)包裝成更易用的方法，讓我們更容易與 Ethereum 互動並發送請求。

Hardhat 讓整合[外掛](https://hardhat.org/plugins/)以取得額外工具與延伸功能變得非常簡單。我們會使用 [Ethers 外掛](https://hardhat.org/plugins/nomiclabs-hardhat-ethers.html)來部署合約（[Ethers.js](https://github.com/ethers-io/ethers.js/) 有一些非常簡潔的合約部署方法）。

在你的專案目錄中輸入：

在下一步中，我們也會在 **hardhat.config.js** 裡引入 ethers。

## 步驟 13：更新 hardhat.config.js

到目前為止我們已經新增了幾個相依套件和外掛，現在需要更新 **hardhat.config.js**，讓我們的專案知道這些設定。

將你的 **hardhat.config.js** 更新成這樣：

## 步驟 14：編譯我們的合約

為了確認到目前為止一切正常，讓我們編譯合約。compile 是 hardhat 內建任務之一。

在命令列執行：

你可能會看到一則關於原始檔案未提供 SPDX license identifier 的警告，但不用擔心——希望其他部分都沒問題！如果有問題，你可以從 Alchemy Dashboard 開啟支援單。

## 步驟 15：撰寫部署腳本

現在合約已經寫好，設定檔也準備妥當，接下來要撰寫合約部署腳本。

到 **scripts/** 資料夾，建立一個新檔案叫 **deploy.js**，加入以下內容：

Hardhat 在他們的[合約教學](https://hardhat.org/tutorial/testing-contracts.html#writing-tests)中對每一行程式碼的作用都有非常好的說明，我們在這裡沿用了他們的解釋。

[ethers.js](https://www.alchemy.com/dapps/ethers-js) 中的 **ContractFactory** 是用來部署新智慧合約的抽象概念，因此這裡的 MyNFT 就是我們 NFT 合約實例的工廠（factory）。使用 **hardhat-ethers** 外掛時，**ContractFactory** 和 **Contract** 實例預設會連接到第一個 signer。

在 **ContractFactory** 上呼叫 **deploy()** 會開始部署，並回傳一個會解析為 **Contract** 的 **Promise**。這個物件包含對應我們智慧合約每個函式的方法。

## 步驟 16：部署我們的合約

我們終於準備好部署智慧合約了！回到專案目錄的根目錄，在命令列執行：

接著你應該會看到類似這樣的內容：

如果我們前往 [Sepolia Etherscan](https://sepolia.etherscan.io) 搜尋我們的合約地址，應該能看到它已經成功部署。這筆交易看起來會像這樣：

<ImageBlock
  src="https://media.alchemy.com/1704803201-ropsten-etherscan.png"
  alt="Etherscan 交易畫面，確認 NFT 智慧合約已成功部署"
  width={2880}
  height={1646}
  caption="地址部署成功"
/>

**From** 地址應該會與你的 Metamask 帳號地址相符，而 To 地址則會顯示「Contract Creation」。如果點進這筆交易，我們會在 **To** 欄位看到我們的合約地址：

<ImageBlock
  src="https://media.alchemy.com/1704803309-nft-deployed-successfully.png"
  alt="太棒了！你剛把 NFT 智慧合約部署到 Ethereum 鏈上 🎉"
  width={2880}
  height={1538}
  caption="太棒了！你剛把 NFT 智慧合約部署到 Ethereum 鏈上 🎉"
/>

想了解背後實際發生的事情，讓我們前往 [Alchemy dashboard](https://dashboard.alchemy.com/signup?referral=affiliate:68212b46-a5c5-4f4c-bc8b-73f50536fcaf) 的 Explorer 分頁。如果你有多個 Alchemy App，記得依 App 篩選，選擇「MyNFT」。

<ImageBlock
  src="https://media.alchemy.com/1704803382-navigate-to-the-explorer-tab-in-our-alchemy-dashboard.jpg"
  alt="Alchemy 儀表板的 Explorer 分頁，列出合約部署期間發出的 JSON-RPC 呼叫"
  width={2880}
  height={1636}
  caption="前往 Alchemy 儀表板的 Explorer 分頁"
/>

在這裡你會看到一系列 JSON-RPC 呼叫，這些都是我們呼叫 **.deploy()** 函式時，Hardhat/Ethers 在背後為我們發出的請求。

這裡有兩個值得特別說明的呼叫：**`eth_sendRawTransaction`**，這是實際將我們的智慧合約寫入 Sepolia 鏈上的請求；以及 **`eth_getTransactionByHash`**，這是根據交易雜湊值讀取交易資訊的請求（發送交易時的一種常見模式）。

想了解更多發送交易的細節，可以查看這篇關於[用 Web3 發送交易](https://docs.alchemy.com/docs/how-to-send-transactions-on-ethereum)的教學。

本教學第一部分到此結束。在第二部分，我們會實際透過[鑄造 NFT](/blog/how-to-mint-an-nft-using-web3-js) 來操作我們的智慧合約，第三部分則會說明如何[在 Metamask 中查看你的 NFT](/blog/how-to-view-your-nft-in-your-mobile-wallet)！🤑
