iT邦幫忙

2022 iThome 鐵人賽

DAY 13
0
Web 3

Road Map To DApp Developer系列 第 13

【DAY13】 - Mint button & Connect With Smart Contract

  • 分享至 

  • xImage
  •  

Preface

今天要來完成的是 Mint Button 並讓 MetaMask 送出交易,並與 Provider 連動,與我們在鏈上的合約完成互動,呼叫 mintForAudience() 這個函式,mint 複數張的 ERC1155 ticket 到使用者的地址中。

Mint Flow

首先先梳理一下整個運作流程。

  1. Home 頁面會讓使用者選擇兩個身分:Staff or Audience。
  2. 點入後會分別進入兩個不同的 mint 頁面(這邊為了避免測試時過於複雜,只使用了 Audience 的 ticket mint 頁面)。
  3. 頁面上會顯示: Choose How Many Tickets You Want to Mint.
  4. 頁面上可以讓使用者調整它需要 mint 幾個
  5. 按下 mint 鍵可以跳出 Metamask 送出交易
    • 如果按下 mint 時沒有連接錢包,會跳出 alert 說需要連接錢包。
    • 如果 MetaMask 的 network 不是指向 mumbai network 則要讓使用者 switch network。
    • 如果 mint 數量小於 0,按下 mint 後會跳出 alert 說數量要大於 0。
  6. 額外要求mint 成功後可以跳出 mint 成功的資訊,可以在哪個網址看到。

實作

一、Home 頁面會讓使用者選擇兩個身分:Staff or Audience。

在這個 project 裡面,我使用了 React-router-dom 這個套件來使頁面載入的速度加快。

App.js 的程式中可以看到這樣的語法:

import {BrowserRouter as Router, Route, Switch} from 'react-router-dom';

<Router>
    <div className="App">
        <Navbar />
        <div className="content">
            <Switch>
                <Route exact path="/">
                    <Home />
                </Route>
                <Route path="/Mint/Audience">
                    <Mint />
                </Route>
            </Switch>
        </div>
    </div>
</Router>

其中 <Switch> 中的 <Route> 可以代表每一個頁面,其中的 path 代表著此頁面的路徑,例如 <Mint> 的絕對路徑就是:http://localhost:3000/Mint/Audience )。

而我們如何在頁面中做出一個可以連結到此路徑的 link?其實很簡單,同樣

import {Link} from 'react-router-dom'

接著直接使用 Link tag 便可以讓這個連結指向你的 Route 的路徑。

<Link to={'Mint/Audience'}></Link>

而昨天我設計並完成了登入的介面,但是並沒有做出 Home 這個頁面,後來使用 Router 做出下方成果。

二、點入後會分別進入兩個不同的 mint 頁面

跳過XD!(這部分因為時間問題,我應該不會再做)

三、頁面上會顯示: Choose How Many Tickets You Want to Mint.

在頁面上顯示:Choose How Many Tickets You Want to Mint.

四、頁面上可以讓使用者調整它需要 mint 幾個。

這邊簡單的設置了一個計數器(就是 javascript 基本課程會上的那種XD)

<div className="mint-Count">
    <button className="plus" onClick={ () => setMintNum(mintNum - 1)}>-</button>
    <div className="mint-num">{ mintNum }</div>
    <button className="minus" onClick={ () => setMintNum(mintNum + 1)}>+</button>
</div> 

宣告一個 useState:mintNum,並在增減的時候使用 setMintNum(mintNum (operator) 1) 便可以達成增減的效果。

五、按下 mint 鍵可以跳出 Metamask 送出交易。

首先我使用了 web3.js 這個套件。web3js 是一個頗為古老的 js 套件,可以讓使用者與遠端的 Ethereum 區塊鏈互動,如送出交易、查看鏈上資訊等。

cd 到 project 裡面 console 輸入下面指令安裝套件

npm install web3

先宣告一些變數,provider、contractAddress 與 mumbai ID

const web3 = new Web3(Web3.givenProvider);
const ticketAddress = "0xfEFBA989dBf2027745262940F02C41193C90Af62";
const mumbaiId = 80001;

1. 錢包是否連接

第一步是需要確認錢包是否連接,這時可以利用 Home page 傳過來的 accounts 來確定是不是目前是否有帳號連接

const isConnected = Boolean(account2[0])

2. Network 是否正確

第一步是如果沒有連接,則跳出訊息,叫使用者 Connect。這邊使用 window.etherum 中的 networkVersion value,可以偵測 network 是否為我們指定的。如果不是的話,就送出 window.ethereum.request({ wallet_switchEthereumChain, params: [<network Items>]})

const switchNetwork = () => {
    if (!isConnected) {
        alert('Please connect to MetaMask!');
        return;
    }

    if (window.ethereum.netWorkVersion !== mumbaiId){
        try {
            window.ethereum.request({
            method: 'wallet_switchEthereumChain', 
            params: [{ chainId: web3.utils.toHex(mumbaiId) }]
            });
        }

        catch (err) {
            // This error code indicates that the chain has not been added to MetaMask
            if (err.code === 4902) {
                window.ethereum.request({
                method: 'wallet_addEthereumChain',
                params: 
                [{
                    chainName: 'Polygon Testnet',
                    chainId: web3.utils.toHex(mumbaiId),
                    nativeCurrency: { name: 'MATIC', decimals: 18, symbol: 'MATIC' },
                    rpcUrls: ['https://rpc-mumbai.maticvigil.com/']
                }]
                });
            }
        }
    }
}

3. 送出 mint function

在先前介紹 Provider 時,我們知道單只有管理私鑰的 wallet 是不能自行送交易到 Ethereum 中的,需要透過 provider 來與區塊鏈互動。

因此需要透過 Web3.getProvider 可以讓我們得到 browser 中的 provider 是誰。

另外 Wallet 可以透過私鑰來簽屬(signature)交易,再透過 Provider 將這筆交易傳遞到全節點中。而與鏈上互動的方式可以分成兩種:

1. read:
若以 webjs 而言的話就是:

web3.contract.methods.Mymethod(parameters).call()

call function 並不會改動任何鏈上 storage 的資料,只會 return 鏈上儲存的資訊。

2. write:

web3.contract.methods.Mymethod(parameters).send()

send function 則可以改動鏈上的資料,也就代表會這筆交易會執行鏈上的 function。

而我們要使用的就是第二種方法。

const ticketContract = new web3.eth.Contract(abi, ticketAddress);
ticketContract.methods.mintForAudience(mintNum).send({
    from: window.ethereum.selectedAddress
    })
    .on('error', (error, receipt) => {
      // emit when there is an error
      console.log(receipt);
    })

透過上述的方式便可以讓使用者在按下 mint button 後成功的 mint 到 ticket 了!

六、mint 成功後可以跳出 mint 成功的資訊,可以在哪個網址看到。

最後一步應該是最有挑戰性的,但是最後發現其實很簡單。

我們在上一步中使用 contract.methods.function().send(),而這個 method 事實上就會回傳我們想要的東西:transactionHash,我們可以透過這個 hash 與 mumbai polygon 的網址做結合,便可以得到這個交易所在的位置!

.on('transactionHash', (hash) => {
    setTxSend(true);
    setTxLink(prefix + hash); // prefix="https://mumbai.polygonscan.com/tx/"
});

Presentation

下面則是網頁的最終結果:

可以在 Polygon Scan 上看到成功 mint 了兩個 id=3 的 token!

Closing

今天的內容,除了 Switch network 還有 mint function 有參考 Stackoverflow 上的寫法外,算是我用手一行一行慢慢地刻出來的,有一種慢慢的把一個小孩培養長大的感覺XDD。

而且最後一點:讓交易的網址可以顯現出來其實是我的一個額外想法。因為原本我前陣子做的 project -- BAKAJOHN 的網頁在 mint 後並沒有產生任何反應,我自己覺得是非常不符合使用者體驗的。原本以為這個功能會特別難做,沒想到最後成功地做出來了,非常的開心!

雖然成功的寫出了我想要的流程,但是我覺得有一些細節我還是沒有處理的很好,例如在 send transaction 後,應該是要等到 transaction 成功的被包在一個區塊中(在 Polygon 上的狀態為 success),才能被顯現出來,而在等待途中應該用「Loading...」來顯示等待中。

另外也有很多關於 web3 provider 的功能我也尚未完全了解,希望可以透過這個專案再學到更多。且由於 webjs 算是一個頗為古老的函式庫,我在未來也需要學習用 etherjs 等較新的函式庫來進行開發會更為時宜。

References


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

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


上一篇
【DAY12】 - Connect MetaMask Wallet!
下一篇
【DAY14】 - Fetch Data From Opensea
系列文
Road Map To DApp Developer30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言