---
# System prepended metadata

title: 第四次實作練習｜智能合約與 Dapp 實戰讀書會

---

# 第四次實作練習｜智能合約與 Dapp 實戰讀書會
> 已公佈實作參考解答

[TOC]

## 實作說明
第四次讀書會實作主題是「前端 Web3 與智能合約串接」，會讓大家練習寫一個前端並且是可以和部署在鏈上的智能合約作互動的。

繳交作業必須完成 ==串接智能合約實戰 基本題==，進階題可做可不做，請<u>**在 12/16 (五) 23:59前**</u>繳交

**注意事項：**
1. 本作業採 React 方式，需用 git clone 下來後並安裝相依套件，在本地上跑 localhost
    👉 [Github Repo: batch4-week6-mint](https://github.com/Krypto-Camp/batch4-week6-mint)
2. 智能合約已部署至鏈上，智能合約程式碼在 `contracts/KryptoCampNft.sol`，一個錢包最多只能 mint 三個 NFT，其他請再自行看智能合約規則
3. 前端畫面已刻完，請全域搜尋 TODO: 已標記需完成的三個 function
    -    一個 TODO 在 `Navbar.js`
    -    兩個 TODO 在 `MainMint.js`
5. 若對 git 不熟的同學，請再回到平台回放 git 相關線上課程
6. 籌備團隊會實測專案，確認是否可完成基本功能
7. 部署部分可參考平台前面錄影的 Netlify，或自行試試部署至 Vercel

## 練習繳交說明
提醒，繳交作業標題：請填寫於 Discord 群組的名稱，例：`DApp_中文姓名_英文姓名`

以 Hackmd 方式繳交，==請務必務必務必一定要將閱讀權限公開==！！
- 提供你的 github 連結：
- 若有部署前端，請提交你的網址：


## 串接智能合約實戰 基本題
**實作目標：**
1. 使用者可以連接 Metamask 錢包
2. 讀取智能合約的 totalSupply，並寫入畫面上
3. 點擊 mint 按鈕，會呼叫智能合約的 mint Function，讓使用者可以購買 NFT


### 參考解答
==**A. 連接 Metamask 錢包**==
```javascript=
/* Navbar.js */
  // TODO: 連接錢包
  async function connectAccount() {
    if (window.ethereum) {
      const curAccount = await window.ethereum.request({
        method: 'eth_requestAccounts'
      })
      setAccounts(prev => [...prev, curAccount]);
    }
  }
```

==**B. 與合約互動顯示出 totoalSupply**==
```javascript=
/* MainMint.js */
  // TODO: 呼叫合約 totalSupply 方法，並寫入到變數 totalSupply
  const getNFTTotalSupply = async () => {
    const provider = new ethers.providers.Web3Provider(window.ethereum);
    const KryptoCampContract = new ethers.Contract(
      KryptoCampNFTAddress,
      kryptoCampNFTAbi,
      provider
    );
    const currentSupply = await KryptoCampContract.totalSupply();
    const amount = ethers.utils.formatUnits(currentSupply, 0);
    setTotalSupply(amount);
  }
```

==**C. 依照點選數量，mint 出 NFT**==
```javascript=
/* MainMint.js */
  // TODO: 呼叫 Contract mint fn
  const handleMint = async () => {
    if (window.ethereum) {
      // TODO: 1) 設定 Provider
      const provider = new ethers.providers.Web3Provider(window.ethereum);
      // TODO: 2) 設定 signer
      const signer = provider.getSigner();
      // TODO: 3) new Contract 實體
      const KryptoCampContract = new ethers.Contract(
        KryptoCampNFTAddress,
        kryptoCampNFTAbi,
        signer
      );
      try {
        // TODO: 4) 呼叫合約 mint 方法
        console.log(mintAmount);
        const mintPrice = 0.01;
        const response = await KryptoCampContract.mint(mintAmount, {value: ethers.utils.parseEther((0.01 * mintAmount).toString(), 'ether')});
        
        console.log('response', response);
      } catch ({ error }) {
        showToast(error.message)
        console.error('[Error]', error)
      }
    }
  }
```


### 細節補充：React Hook
- [useState 介紹](https://ithelp.ithome.com.tw/articles/10220063)
- [各類資料型別的 useState](https://daveceddia.com/usestate-hook-examples/)
- [useEffect 介紹](https://reactjs.org/docs/hooks-effect.html)
- [useEffect 範例介紹](https://ithelp.ithome.com.tw/articles/10224270)


### 細節補充：相關文件
- [Nodejs](https://nodejs.org/en/)
- [Metamask Docs](https://docs.metamask.io/guide/)
- [ChainId List](https://docs.metamask.io/guide/ethereum-provider.html#basic-usage)


## 串接智能合約實戰 進階題
> 進階題可不做，但需繳交基本題


1. 當使用者 Metamask 錢包不在 Goerli 測試鏈時，可跳出狐狸視窗半強迫性，請使用者切換至 Goerli 鏈
2. 將前端網站部署至 Vercel, Netlify 等網站，可直接透過網址進入 KryptoCamp 購買 NFT

### 參考解答
==**A. 當網路不是 Goerli 時，會跳出 prompt 要 switch network**==
```javascript=
/* MainMint.js */
  const switchNetwork = async () => {
    await window.ethereum.request({
      method: 'wallet_switchEthereumChain',
      params: [{
        chainId: '0x5'
      }]
    })
  }
  
  const getNetwork = async () => {
    const provider = new ethers.providers.Web3Provider(window.ethereum);
    const { chainID } = await provider.getNetwork();
    setCurrentChainID(chainID);

    // Goerli Testnet ChainID is 5
    if (chainID !== 5) { switchNetwork(); }
  }
  
  useEffect(() => {
    if (window.ethereum) {
      getNetwork();
      getNFTTotalSupply();

      // Listening to changes
      window.ethereum.on('networkChanged', (networkId) => {
        if (networkId !== 5) { window.location.reload(); }
      })
    }
    else {
      showToast('Please get your Web3 wallet first')
    }
  }, [])
```

==**B. 部署至 Vercel, Netlify 上**==

- [Vercel 官網文件](https://vercel.com/docs/concepts/git/vercel-for-github)
- [Vercel Step by Step Tutorial](https://vercel.com/docs/concepts/get-started/deploy)