iT邦幫忙

2022 iThome 鐵人賽

DAY 5
0
Web 3

Road Map To DApp Developer系列 第 5

【DAY5】 - ERC721 (Mint Your 1st NFT)

  • 分享至 

  • xImage
  •  

【DAY5】 - ERC721 (Mint Your 1st NFT)

前言

在前一篇中介紹了 ERC721 的功能以及價值,但是了解了這些東西仍離真正的接觸 NFT 還有一段距離。因此這篇我想要講解如何 deploy 一個 ERC721 的 contract 到鏈上,並用自己的 metamask 錢包 mint 一個專屬於自己的 NFT。但是這那之前會先介紹一下 ERC721 的功能有哪些。

P.S. 雖然上一章有提及了 ERC20 的函式,但是有些功能如 mint()burn() 不包含在那些基本的函式中,通常是只有做 ICO 的人會使用到的函式,如果有興趣的可以看這個合約內容

ERC721

ERC20 Compatible Functions

下面幾個是與 ERC20 中相同的 function,基本上功能就與 ERC20 token 一模一樣,因此不再贅述。

function name() constant returns (string name);
function symbol() constant returns (string symbol);
function totalSupply() constant returns (uint256 totalSupply); // 總供給量
function balanceOf(address owner) constant returns (uint balance) // owner 的 token 數

ERC721 協議中的 function 總共有 10 個,event 共 3 個。

ERC721 其他 function

contract ERC721 is ERC165{ // 需要繼承 ERC165
    function ownerOf(uint256 tokenId) external view returns (address owner);

    function approve(address _to, uint256);
    function takeOwnership(uint256 _tokenId);
    // Function Overloading
    function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable;
    function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;
    function transferFrom(address _from, address _to, uint tokenId) external payable;

    function approve(address _approved, uint256 _tokenId) external payable;
    function setApprovalForAll(address _operator, bool _approved) external;
    function getApproved(uint256 _tokenId) external view returns(address);
    function isApprovedForAll(address _owner, address _operator) external view returns (bool);

    event Transfer(address _from, address _to, uint256 tokenId);
    event Approval()
    event ApprovalForAll()
}

Functions

ownerOf(uint256 tokenId) -> address

  • 由於 ERC721 token 每一張是不同的,因此每一張 token 都有屬於自己的 tokenId(通常這個 Id 是由發行的順序決定的)。這個函式可以透過輸入 tokenId 來找尋到這張 token 的擁有者。
  • 通常這種關係會使用 mapping 來儲存,大概會長:
mapping (uint256 => address) ownerOf;
// 輸入 tokenId=0 的 owner 
ownerOf[0] = 0x5c6B0f7Bf3E7ce046039Bd8FABdfD3f9F5021678
  • 如果回傳的是 zero address (0x0000...000) 代表這枚 token 還沒有人所有。

safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data)

  • _fromtoken 所有權轉移_to
  • safetransferFrom() 限制了下面幾件事:
    1. _from_to 不能為 zero address。
    2. ownerOf(_tokenId) == _from
    3. msg.sender (call 這個 function 的地址)需為_from 或是經過 approved() 的地址或是此 token 被 setApprovalAll()
    4. 如果 _to 是一個合約地址,會 call 那個合約中的 onERC721Received()
  • 注意:若直接用 transferFrom() 將 token 轉到一個 zero address,會直接讓這個 token 變成一個遺失物,因此現在多建議使用 safetransferFrom() 而不用 transferFrom() 了。

approve(address _to, uint256 tokenId)

  • 將此 token 的交易權交給其他地址來執行。
  • 經過 approve() 後的地址可以執行 safeTransferFrom() 來進行交易。
  • msg.sender 需要是 NFT 的擁有者或是經過 approve() 的地址,且這個地址同一時間只會有一個,因此如果今天某個 approve() 後的地址呼叫了這個 function,但是他做了這件事approve(0,tokenId),此時 approve() 的地址就會被清除。
  • 會 emit Approval()

setApprovalAll(address _operator, bool _approved)

  • 將此 token 的交易權轉交給第三方(也就是上方的 operator)執行,有點像是把一件拍賣商品放到拍賣所(opensea),委託他們進行拍賣。
  • 而後方的 parameter:
    • _approved == true: 代表 operator 擁有交易權
    • _approved == false: 代表撤回 operator 的權力
  • 會 emit ApprovalForAll()

Events

Transfer()

Transfer() 會在 token 交易的時候 emit 出來,可能會有三種情況:

  • 如果 _from 是 0 代表這筆交易是 mint token
  • 如果 _to 是 0 代表這筆交易是 burn token
  • _from_to 都不是 0 代表是正常的交易。

Mint

Mint (verb) : to produce a coin for the government (取自劍橋辭典)

在實作之前,我想再介紹一個概念 -- MINT。Mint 的中文為鑄造錢幣的意思(這邊不是指薄荷:)),而一種 ERC721 token 可能會使用兩種方式來鑄造 token。

  1. 直接由項目方 mint 後,交由第三方的拍賣方(opensea)做後續交易。但是對於項目方來說需要付出大筆的 gas fee,因此通常較少人使用。
  2. 客戶端由項目方的網站中 mint,有些網站可以設置不同的 mint 數量,但是每次客戶 mint 都需要花費一定價值的 gas fee。流程可見下圖。

實作部分!

以下的部分會只有合約的內容,並利用 remix 來做函式呼叫。

1. Openzepplin wizard

首先第一個步驟先打開 Openzepplin 的官網,進入 Contract,找到 Contract 中的 Docs,在左邊的欄位選擇 wizard,將會顯示下面的畫面。

這個 wizard 有點像一個模板,你可以選擇你想要的 token 種類,裡面需要什麼功能,wizard 就會自動的幫你放上去,並且 import Openzepplin 自己的合約。

  • 在 Name 中輸入 FirstToken、Symbol 輸入 FT(也可以輸入你想要的名稱哈哈)。
  • Feature 中勾選 Mintable + Auto Increment Ids。這一步的目的是讓這個合約可以執行 mint,以及可以自動的改動 tokenId。
    接下來就會在右邊顯示:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";

contract FirstToken is ERC721, Ownable {
    using Counters for Counters.Counter;

    Counters.Counter private _tokenIdCounter;

    constructor() ERC721("FirstToken", "FT") {}

    function safeMint(address to) public onlyOwner {
        uint256 tokenId = _tokenIdCounter.current();
        _tokenIdCounter.increment();
        _safeMint(to, tokenId);
    }
}
  • Counter: 他其實就是一個用來計算 tokenId 的 Library,可以見 Openzepplin 的合約內容
    • 第一個宣告的 _tokenIdCounter 是一個 structure,其中 attribute 是一個 uin256。
    • .current(): 回傳現在的 tokenId。
    • .increment(): 現在的 tokenId += 1。
  • ownerable: 是一個 modifier,可以確認 msg.sender 是不是 該 NFT 的 owner
  • _safeMint: 將新的一枚 token mint 到 to 的帳戶中。

Deploy

Metamask

接下來需要大家先安裝 chrome/edge/firefox/brave 或其他瀏覽器上的 Metamask,關於創立帳戶,這邊有更仔細的教學。

在安裝完小狐狸錢包後,需要測試網中的測試幣,連接這邊的水龍頭領取!(這邊使用的是 goerli 測試網)

進入後將你 metamask 的地址輸入,裡面的合約就會送 goerli ETH 給你了。(但上述的 faucet 需要登入 Alchemy 的帳號才可以拿到)
拿到後你可以在 metamask 中將你的網路改變成 goerli testnet,確認是否得到了 ETH。


Deploy Contract

隨後我們把剛剛的 wizard 中拿到的程式碼,複製到 remix(一種 IDE)上並貼上!我自己是在 workspaces 創立一個新的 blank 專案,並放入 Day5_First_NFT.sol 中。

並將 deploy(預設應該是由上數下來的第四個)中的 environment 設為 Injected Provider - Metamask,metamask 便會跳出來叫你登入(記得網路要選擇 goerli testnet)。

登入後,在 CONTRACT 選擇 FirstToken (或你自己取的合約名稱),按下 deploy!此時就會跳出這個畫面:

按下後這張合約就成功的 deploy 在測試鏈上了。


Mint

接下來點入下方的 Deployed Contracts,展開後可以看見一堆 function,找到 safeMint,並在 address to 中輸入你自己的地址。再次的送出交易,成功後擬就成功的 mint 你的第一個 NFT 了!

可以再用下面的 function 來看看這枚 token 是否真的到了你的地址中。像是 ownerOf 中輸入 0(第一枚 mint 出來的編號是 0 XDD)。

小結

Openzepplin 的合約真的是一個好東西,除了方便(你只需要 import 他們的合約就可以完成很多事情)以外安全性也很棒!我也觀察到其實很多 NFT 項目方也使用他們的合約來 deploy,所以是值得信任的!另外 NFT 也有一個大重點會在明天提到,請大家期待一下哈哈!

References


若有文章內有任何錯誤的地方歡迎指點與討論!非常感謝!

歡迎贊助窮困潦倒大學生
0xd8538ea74825080c0c80B9B175f57e91Ff885Cb4


上一篇
【DAY4】 - ERC721 Token ( Introduction)
下一篇
【DAY6】 - ERC721 的核心
系列文
Road Map To DApp Developer30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言