มาลองสร้าง dApp ด้วย Web3.js แบบง่ายๆกันเถอะ ตอนที่ 2 เชื่อมต่อ Wallet ด้วย Metamask

T Siriwat
Under Ledger
Published in
3 min readJul 6, 2022

จาก Blog ที่แล้วเราได้ทำโครงสร้างหน้าเว็บของเราเรียบร้อยแล้วในตอนนี้เราจะมาลอง Connect Wallet ด้วย Metamask แล้วลองใช้ Event Listener ต่างๆกันครับถ้าหากใครยังไม่ได้ดูตอนที่แล้วสามารถเข้าไปดูได้ที่นี้เลยครับ

ก่อนอื่นเลยเราจะต้องมี extension Metamask บน Browser ของเราก่อนซึ่งสำคัญมาก หากใครยังไม่มีก็ติดตั้งและสร้างกระเป๋าให้เรียบร้อยก่อนซึ่งในตอนนี้เราจะข้ามวิธีติดตั้งไปก่อน ถัดมาเราก็จะต้องลง Package web3 โดยใช้คำสั่ง

npm install web3 -S

เมื่อลงเสร็จแล้วต้อง Config อะไรเพิ่มเติมนิดนึง โดยให้เพิ่ม devDependencies ใน package.json จะได้ดังนี้

"devDependencies": {
"assert": "^2.0.0",
"buffer": "^6.0.3",
"crypto-browserify": "^3.12.0",
"https-browserify": "^1.0.0",
"os-browserify": "^0.3.0",
"process": "^0.11.10",
"react-app-rewired": "^2.2.1",
"stream-browserify": "^3.0.0",
"stream-http": "^3.2.0",
"url": "^0.11.0"
}

จากนั้นคำสั่ง npm install เพื่อติดตั้งdevDependencies ที่เราเพิ่มเข้าไปใหม่และถัดไปก็แก้ไข scripts จาก react-scriptsเป็น react-app-rewired ใน package.json จะได้ดังนี้

"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test",
"eject": "react-app-rewired eject"
}

สุดท้ายแล้ว สร้างไฟล์ชื่อ config-overrides.js จากนั้นเพิ่ม Config ดังนี้

const webpack = require("webpack")module.exports = function override(config) {
const fallback = config.resolve.fallback || {}
Object.assign(fallback, {
crypto: require.resolve("crypto-browserify"),
stream: require.resolve("stream-browserify"),
assert: require.resolve("assert"),
http: require.resolve("stream-http"),
https: require.resolve("https-browserify"),
os: require.resolve("os-browserify"),
url: require.resolve("url"),
})
config.resolve.fallback = fallback
config.plugins = (config.plugins || []).concat([
new webpack.ProvidePlugin({
process: "process/browser",
Buffer: ["buffer", "Buffer"],
}),
])
return config
}

จากนั้นเราก็จะลองรันโปรเจคของเราหลังจากติดตั้ง web3 โดยคำสั่ง npm start

http://localhost:3000

จากนั้นเราจะมาทำ Connect Wallet กันครับ โดยก่อนอื่นเลยไปที่ src/App.js เพื่อเพิ่ม State และ Function และนำไปจัดการ Connect Wallet

const [wallet, setWallet] = useState({address:"", balance: 0})const onConnectWallet = (wallet) => {
setWallet(wallet)
}
<Navbar
wallet={wallet}
onConnectWallet={onConnectWallet}
/>
//<Modal/> ขอ Comment ไว้ก่อนเพราะ Modal บังเพื่อนอยู่

จากนั้นเราจะเพิ่ม {wallet, onConnectWallet}ที่ส่งมาจากหน้า src/App.js ให้กับ src/Navbar.js และนำ wallet, onConnectWallet มาใช้จะได้ดังนี้ (ขอแอบ import web3 มาด้วย)

import Web3 from "web3"
import { shortenAddress } from "./shortenAddress"
const Navbar = ({wallet, onConnectWallet}) => {
...
{wallet.address!=="" && <p ...>Amount : {wallet.balance} 🪙</p>}
<button ...
onClick={()=> handleConnectWallet())}
>
{wallet.address !== ""? shortenAddress(wallet?.address): "Connect Wallet"}
</button>
...
}

แล้วสร้างไฟล์เก็บไว้ที่ src/components/shortenAddress.js แล้วเพิ่มโค้ดดังนี้เลย

export const shortenAddress = (address) => `${address.slice(0, 5)}...${address.slice(address.length - 4)}`

จากนั้นเราจะเพิ่มฟังก์ชั่น handleConnectWallet เมื่อกดปุ่ม Connect จะมี Popup จาก Metamask มา Confirm ว่าจะ Connect กับเว็บไซต์นี้รึเปล่า โดยโค้ดจะมีดังนี้

const handleConnectWallet = async() => {
const web3 = new Web3(window.web3.currentProvider)
await window.web3.currentProvider.request({ method: "eth_requestAccounts" })
const userAccount = await web3.eth.getAccounts()
const ethBalance = await web3.eth.getBalance(userAccount[0])
eventListener()
onConnectWallet({address: userAccount[0], balance: Number(Web3.utils.fromWei(ethBalance, "ether")).toFixed(4)})
}

แล้วก็เราจะเพิ่มฟังก์ชั่น isConnectWallet เอาไว้เช็คเมื่อเปิดเว็บ ว่าเราได้มีการ Connect Wallet กับเว็บของเราไว้หรือไม่ โดยโค้ดจะมีดังนี้

import { useEffect } from "react"const isWalletConnect = async () => {
if(window.web3.currentProvider){
const web3 = new Web3(window.web3.currentProvider)
await window.web3.currentProvider.request({ method: "eth_accounts" })
const userAccount = await web3.eth.getAccounts()
const ethBalance = await web3.eth.getBalance(userAccount[0])
eventListener()
onConnectWallet({address: userAccount[0], balance: Number(Web3.utils.fromWei(ethBalance, "ether")).toFixed(4)})
}else{
onConnectWallet({address: "", balance: 0})
}
}
useEffect(()=>{
isWalletConnect()
},[])

สุดท้ายจะเป็นฟังก์ชั่น eventListener โดยจะเป็นการเช็ค Event ต่างๆที่เกิดขึ้นบน Metamask อ่านเพิ่มได้ได้ที่นี่ โดยที่เราจะลองใช้มี
accountsChanged เป็น Event จับการสับเปลี่ยน Account บน Metamask
chainChanged เป็น Event จับการสับเปลี่ยน Chain บน Metamask

const eventListener = () => {
window.web3.currentProvider.on("accountsChanged", (accounts) => {
if (accounts.length > 0) {
isWalletConnect()
} else {
onConnectWallet({address: "", balance: 0})
}
})
window.web3.currentProvider.on("chainChanged", (chainId) => {
isWalletConnect()
})
}

เมื่อเราทำทุกอย่างถูกต้องแล้ว เราก็จะได้เว็บไซต์ที่สามารถเชื่อมต่อ Wallet ด้วย Metamask ได้ดังนี้

ตัวอย่างการ Connect Wallet และ Swap Chain/Account

เมื่อนำทุกส่วนที่เราทำมาข้างต้นถูกต้อง จะประกอบร่างได้ดังนี้

ในตอนนี้เราก็ได้ลอง Connect Wallet ด้วย Metamask และลองใช้ Event Listener ต่างๆกันแล้ว เดียวตอนถัดไปเราจะมาลองเขียน Smart Contract ของเว็บไซต์ข่าวของเราแบบง่ายๆกันครับ

ถ้ามีผิดพลาดตรงไหนก็ขออภัยด้วยนะครับ และสุดท้ายนี้ก็ขอขอบคุณทุกคนที่หลงเข้ามาอ่านถึงตรงนี้นะครับ

--

--