更新於 2024/12/04閱讀時間約 13 分鐘

NextJS & HTML 實作 ERC20 交易網站【開發筆記】

2022/06/10 發佈於 Medium
說是開發過程的筆記,應該是撞牆心血錄,因為各式各樣的原因,所以為前後端串接困擾了很久⋯⋯在這邊想特別感謝 Pecu老師的指點,如果沒有老師給的新思路,我可能會撞牆撞到天荒地老 QQ

前置作業

  • NodeJS 環境(建議先安裝 yarn,沒有也沒關係, yarn 與 npm 的轉換可上網搜尋)
  • Metamask 擴充套件下載
  • 完工的 HTML 靜態網站(不是 HTML 也OK,跳過轉檔段落即可)
備註:接下來的程式碼中,實作的 ERC20 合約為 CafeChainCoin,文章則會用 YourToken 代稱,若要使用,把相關設定替換成自己的即可。

發行 ERC20 貨幣合約

OpenZeppelin Contracts Wizard 創建自己的 ERC20 合約,輸入合約名稱 Name、代稱 Symbol、初發行數量 Premint 就基本完成,還可以額外對合約增加設定, 細節可以參考網站內的說明。
實作程式碼(記錄用,建議至 OpenZeppelin Contracts Wizard 創建):
產出合約後,在 Remix 開新 Workspace,創建 YourToken.sol,貼上剛剛完成的程式碼。
到 SOLIDITY COMPILER 的 COMPILER 選擇合約使用的版本,合約版本通常會在程式碼上方,前綴 pragma solidity ^,像我用的是 0.8.4。
接著點擊 Compile YourToken.sol,完成編譯後,到 DEPLOY & RUN TRANSACTIONS,ENVIRONMENT 選擇 Injected Web3,這時會跳出 Metamask 連結彈窗,請務必確認好要發行的鏈與帳號。
CONTRACT 選擇以 Token 命名的那個(像我的是 CafeChainCoin),點擊 Deploy,接著等幾分鐘,成功的話 Deployed Contracts 區就會出現內容。

發行 ERC20 貨幣交易合約

Workspace 開一個 YourTokenVendor.sol,貼上實作程式碼:
tokensPerEther 記得改成自訂 Token 對 Ether 的匯率~
Remix 上發行的步驟都與貨幣合約相同,就只差在最後 Deploy 時,要輸入 Token 的合約地址。完成後,先不要關掉視窗,之後還會回來。

NextJS 環境建置

實際操作畫面可參考大神影片NextJS & Ethers段落前段。
在 VS Code 打開要建 NextJS APP 資料夾的路徑,於 Terminal 輸入
yarn create next-app .
這邊要注意的是,建立 next-app 需要特定 node 版本,如果在這部分有報錯的話,最快的解決方式是直接更到最新版本。
完成建立後,pages 資料夾裡的 car.js 檔可以刪掉。成功的話,這時候跑
yarn dev
Terminal 會跳一個 ready url,複製貼到瀏覽器就可以進到 NextJS 的初始畫面。

把 HTML 嵌進 NextJS APP

轉換方式參考大神影片。
將 HTML 網站的 css、js、images 資料夾複製貼到 public 目錄下。
NextJS Docs 複製 Custom Document 第一段程式碼,進行簡單修改,並直接替換掉 index.js 的程式碼:
import { Head } from 'next/head';
import { Script } from 'next/script';export default function Home() {
 return (
   <>
     <Head>
     <Head/>
   </>
 )
}
將 HTML 檔中被head包起來的 非 script 部分,貼到 index.js 的Head區段中,並將沒被前後夾擊的單行程式碼 替換成 /,大概會長這樣:
<Head>
     <title> ... </title>
     <meta ... />
     <link ... />
<Head/>
接著將 script 貼到Head區段後面(前面也可以),把 script 改成 Script。
<>
     <Head>
           ...
     <Head/>      <Script src="..."></Script>
</>
接著瀏覽器開啟 Transform,左欄選擇 HTML to JSX,把 .html 檔其餘body部分貼到 HTML 區,轉碼後複製右邊 JSX 的程式碼,貼到Head後面,再來因為轉譯器似乎不是很全面,所以需要短短的 debug 時間。
<>
     <Head>
           ...
     <Head/>      ... JSX ...
     
     <Script src="..."></Script>
</>
要注意的是,轉碼後的Input type=”submit”不相近於button,無法觸發 click事件,如果網站有使用,請記得更換。 還有,onclick=要換成onClick=⋯⋯天知道我因為這個卡了多久。

套件安裝

接下來的所有內容參考自:
打開 Terminal,用以下程式碼安裝套件:
yarn add @web3-react/core
yarn add @web3-react/injected-connector
yarn add react
yarn add ethers
yarn add @ethersproject/providers
建議分開執行,這樣有 bug 時比較好 de (?)

把合約資料丟進來

在 NextJS APP 主目錄新增 constants 資料夾,底下開一個 contracts.js,輸入
module.exports = {
     tokenAddress = '你的 ERC20 合約地址',
     vendorAddress = '你的交易合約地址'      tokenABI =
     vendorABI =
}
tokenABI 與 vendorABI 可點擊 Remix SOLIDITY COMPILER 下方的 ABI 鍵複製。
  • tokenABI:CONTRACT 選擇 YourToken(YourToken.sol)
  • vendorABI:CONTRACT 選擇 Vendor(YourTokenVendor.sol)
複製後,直接貼到程式碼等號後面。

寫程式吧!_app.js

打開 _app.js,改!
詳細說明可到 大神影片NextJS & Web3-React段落找一下,只能說 React 永遠的神。

寫程式吧!index.js

點擊 GIF連結 看看呈現的感覺,接下來說明會比較好理解。
流程大概是這樣:
  1. 點擊錢包登入 Metamask
  2. 顯示當前連結帳戶地址
  3. 在「購買」,輸入要購買的 CCO 數量,點擊確認購買就會開始交易
  4. 在「賣出」,輸入要賣出的 CCO 數量,點擊確認購買就會開始交易
那就開始吧!
打開 index.js,在之前轉好 HTML 時完成的部分外,再新增億點點程式碼。return 網頁只有放與 function 相關的部分。
這邊我偷懶把 function跟網站頁面寫在一起,導致程式碼看起來不是那麼俐落,有興趣的話,可以研究一下如何改成 import module的形式。
【學習筆記】
  1. 看不懂就找 大神影片 與 大神文章
  2. useWeb3React() 是紀錄連結 Web3 資訊的強大工具,account 帳戶地址可以直接叫出來!
  3. useState() 函式是用狀態+改變狀態的函式命的,這樣說或許有些饒口,簡單舉例一下,設 const [ apple, setApple ] = useState(0),原本apple=0,想讓蘋果變 1 顆,用 setApple(1) ,就會讓apple=1。
  4. useState() 補充,「改變狀態的函式」可以用各式各樣的方式觸發,像這次就有結合 useEffect()、onChange 事件等,使用邏輯可以參考程式碼。
  5. useEffect() 是另一個新學的函式,顧名思義就是產生影響,詳細介紹可到網路搜尋。
  6. return 中 {variable} 可以在 return 前設定要輸入什麼值,像這裡拿來顯示地址跟存 Input。
這邊的 ETH 轉換是之前撞牆時,寫在前端 JS的(放在 public js 資料夾),有需要可以參考下方程式碼。但當初是因為懶才沒有改到 index.js,轉換還是建議參考 大神文章 ,這樣在做購買時,Token 變數就不用再乘以匯率。
const ccoBuy = document.getElementById('ccoBuy');
const etherBuy = document.getElementById('etherBuy');
const ccoSell = document.getElementById('ccoSell');
const etherSell = document.getElementById('etherSell');ccoBuy.addEventListener('input', (res) => {
     etherBuy.innerHTML = (res.target.value) * 0.01;
});ccoSell.addEventListener('input', (res) => {
     etherSell.innerHTML = (res.target.value) * 0.01;

【開發心血錄】
  1. function buyTokens() 與 sellTokens() 都有擋錯誤 Input 格式的設定,還另外偷偷加了單次交易數額的 Limit,程式是設成數量超過 100 就擋。
  2. Token 系列 function 中有一個我調整了很久的地方,就是 try{} 發送 method 請求部分,當初參考 大神文章 一直報錯,後來改 .send 跟 method 內變數的發送格式才成功,或許是實作方式不同?求了解 QQ
  3. .buyTokens() 中 ccoBuy*0.01,是因為 Input 單位限定為 Ether⋯⋯但 .sellTokens() 單位是 CCO。
  4. ether.utils.parseEther() 會報錯,因爲 utils 是直接從 ethers import⋯⋯當時一直找不到這個 bug 的我,對它愛了很久。
  5. sellTokens() 比 buyTokens() 多了向 Token 合約請求 Approve 的函式,這邊因為 sellTokens() 底下兩個函式都用 await,所以如果 Approve 等太久,會無法揮手送 Vendor 離開。 最後為了解決這個問題,用了 Promise.all。
  6. 這裡 onClick() 跟 onChange() 的內容物不一樣,是因為 onClick 觸發的是無參數函式,可以簡寫,onChange 則需要傳資料出去。
打完程式看可愛貓貓治癒一下
打完程式看可愛貓貓治癒一下
小菜雞寫的程式碼還有許多不足,有誤或想補充的話,歡迎留言一起學習! 以上引用若侵權,經通知會立刻刪除
分享至
成為作者繼續創作的動力吧!
© 2024 vocus All rights reserved.