# 使用 Remix，OpenZeppelin 15 分鐘建立 NFT 智能合約

By [0x0016區塊猿](https://paragraph.com/@0x0016) · 2022-04-03

---

_本文亦發佈在作者網站： 最後更新：2021-03-27_

[https://www.frank.hk/blog/nft-smart-contract/](https://www.frank.hk/blog/nft-smart-contract/)

NTF 最近是街頭巷尾都在討論。關於 NTF 是什麼和 NTF 到底價值在哪裡這裏不做探討。本文純粹是站在技術角度，教一教大家怎樣用代碼寫一個屬於你自己的 NFT。

NFT 是一種Non-fungible token，是基於 ERC721 或 ERC1155 的智能合約而存在。本文演示的是基於 ERC721 的 NFT。（我另外有一篇文章教大家[15分鐘寫 ERC1155 智能合約](https://www.frank.hk/blog/nft-erc1155)，裡面會介紹關於 ERC1155 的內容，有興趣也可以[去看一看](https://www.frank.hk/blog/nft-erc1155)）。

### OpenZeppelin

[OpenZeppelin](https://openzeppelin.com/) 是一個開源的智能合約倉庫，上面已經有許許多多各種各樣的智能合約範本，包括 ERC721 智能合約。因此我們只需要基於 OpenZeppelin 的現有合約，擴展我們自己特定的功能即可。

### 安裝 OpenZeppelin Contracts

確保已經安裝最新版的 NodeJS，運行下面的指令：

    npm install @openzeppelin/contracts
    

之後在當前目錄下就會安裝好 OpenZeppelin Contracts 的檔案。

### 使用 Remix IDE

[Remix](https://remix.ethereum.org/) 是 Ethereum 官方提供的 IDE 。包含完整的編譯器、執行合約、發佈合約等等的功能。無須安裝，只要用瀏覽器開啟 [https://remix.ethereum.org/](https://remix.ethereum.org/) 即可。

Remix 默認情況下會將所有資料存儲在瀏覽器的 Local Storage 中，所以當你清除瀏覽器緩存快取，或者在另外一台電腦打開 Remix，你的資料便會丟失。 Remix 也提供了使用本地文件系統來進行存儲的功能，但需要安裝一個 remixd 本地程式，具體方法可以[參考這裡](https://remix-ide.readthedocs.io/en/latest/remixd.html)。

當你安裝好 remixd 後，便可以透過運行下面的指令來建立 Remix 和本地檔案的連結：

    remixd -s <absolute-path-to-the-shared-folder> --remix-ide <your-remix-ide-URL-instance>
    

### 撰寫智能合約

完成上面的步驟後，我們便可以開始建立自己的 ERC721 合約了。

screen 20210325140218

    // @openzeppelin v3.2.0
    pragma solidity ^0.8.0;
    
    import "../node_modules/@openzeppelin/contracts/token/ERC721/presets/ERC721PresetMinterPauserAutoId.sol";
    
    contract FCAT is ERC721PresetMinterPauserAutoId {
    
        constructor() public
        ERC721PresetMinterPauserAutoId("Frank Cat", "FCAT", "https://www.frank.hk/token/")  
        {}
    
        // This allows the minter to update the tokenURI after it's been minted.
        // To disable this, delete this function.
        function setTokenURI(uint256 tokenId, string memory tokenURI) public {
            require(hasRole(MINTER_ROLE, _msgSender()), "web3 CLI: must have minter role to update tokenURI");
    
            setTokenURI(tokenId, tokenURI);
        }
    }
    

以上的代碼便是利用 OpenZeppelin 的 ERC721 合約建立，我們只是簡單的設置了我們 NFT 的名稱 （Frank Cat），代幣代碼（FCAT）以及代幣 Meta Data URI。

是不是很簡單？

### 編譯，發佈智能合約

編輯完成後， 就可以切換到 Compile 面板進行編譯。留意要選擇正確的編譯器版本，編譯器版本要和你使用的 OpenZeppelin 合約相同，否則會出現編譯錯誤。

screen 20210325140446

編譯完成後，便可以準備發佈（deploy）了。切換到 Deploy 面板。此時我們要在左上角的 Environment 中選擇【Injected Web 3】，此時便會彈出 MetaMask 進行連結。如果還沒有安裝 MetaMask，可以先在 [Chrome Web Store](https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn) 中安裝。

我們開始嘗試時一般都會選擇在測試網路（testnet）中進行，測試網絡和 Ethereum 主網在技術上沒有區別，但在測試網路中不需要花費真實的 ETH ，而是使用測試網路中的 ETH。一般我們開發的 Blockchain 程式，都要先在測試網路上做全面測試，之後才在主網中上線。要知道 Ethereum 主網的 Gas Fee 可高的驚人。

Ethereum 的測試網路有很多，例如 Ropsten， Rinkeby，Goerli 等等。為了能在 OpenSea 上測試，我們選擇 Rinkeby 測試網路。

使用測試網路，記得要在 MetaMask 中選擇 Rinkeby Test Network。

screen 20210325140555

在 Ethereum 網路上任何導致更改數據的動作都需要花費 ETH，因此發佈智能合約自然需要 ETH。如果沒有 testnet 的 ETH 可以在網上找到很多 testnet faucet 可以免費獲得 testnet 的 ETH ，例如[這裡](https://faucet.rinkeby.io/)。一切就緒後，就可以按下 【Deploy】，開始發佈你的智能合約，中間會彈出 MetaMask 進行付款確認。

發佈完成後，Remix 會顯示對應的 Transaction Hash，例如我自己上面的例子，對應的 Transaction 可以在 [https://rinkeby.etherscan.io](https://rinkeby.etherscan.io/tx/0x24ea067b119d0a43e4c4da56b042f318fa7256515845343fcc9d370b266f6b92) 上看到，裡面亦可以看到我們建立的 ERC721 [智能合約地址](https://rinkeby.etherscan.io/address/0x07d2d369813354eb79b1950baaefceb65f8a1112)。

### Mint NFT

合約發佈後，下一步便可以 Mint NFT 啦。

回到 Remix，可以看到 Deployed Contracts 中已經有我們剛才發佈的智能合約，點開他之後可以看到裡面有一個 mint 的 Function，現在我們就可以調用這個 Function 來 Mint NFT 了。在 mint function 後面的 address to 中輸入一個地址，這個地址就會成為新建立的 NFT 的擁有者了。

screen 20210325142316

當 mint 完成後，稍等一段時間便可以在 [OpenSea 中看到對應的 NFT](https://testnets.opensea.io/collection/frank-collections) 已經誕生了！

screen 20210325142748

到這裡其實我們已經完成了一個最基本的 NFT 的建立。但你可能會問為什麼我們剛才建立的 NFT 沒有圖像呢，要怎麼才能像其他 NFT 一樣有圖像以及其他的一些屬性呢？

原來 NFT 對應的圖像以及其他屬性是由 NFT 的 Metadata 決定，要想 NFT 在 OpenSea 中顯示圖像和其他屬性，還需要指定該 NFT 的 Metadata。

### ERC721 Metadata

根據 OpenSea 上的 [ERC721 Metadata 標準](https://docs.opensea.io/docs/metadata-standards)，OpenSea 會調用我們智能合約中的 `tokenURI` function，並傳入 tokenID，而這個 function 需要返回一個 HTTP 或 IPFS URL，這個 URL 則必須返回一個 JSON 格式的數據，例如[我例子中的這個](https://www.frank.hk/pictures/token/3)，而這個 JSON 則定義了我們 NFT 的各種屬性。

meta

用我們上面寫的智能合約為例，留意我們在 constructor 中有如下寫法：

    ERC721PresetMinterPauserAutoId("Frank Cat", "FCAT", "https://www.frank.hk/token/") 
    

其中 `https://www.frank.hk/token/` 便是指定了我們 NFT 的 base URI，當調用 `tokenURI` function 時，我們的合約就會 return `https://www.frank.hk/token/<tokenID>`。

當這個 Metadata 設置好後，再 mint 出的 NFT 就會帶有圖像等屬性了。

screen 20210325155209

screen 20210325155253

當然， 我們建立的 NFT 也是可以在 OpenSea 上交易的哦。

screen 20210325155621

screen 20210325155636

以上就是一個超級簡單的自己寫代碼製作 NFT 的教學了。如果有任何討論，或是錯誤指正，歡迎聯絡我不吝賜教。

感謝閱讀。

技術交流，其他諮詢等，請[按此聯絡](https://www.frank.hk/contact)。

---

*Originally published on [0x0016區塊猿](https://paragraph.com/@0x0016/remix-openzeppelin-15-nft)*
