ทำปุ่ม Connect Wallet + Metamask ด้วย Rainbowkit + Wagmi
สวัสดีครับ โพสนี้มาลองทำเว็บ dApp เพื่อ Connect Wallet ด้วยการใช้ Rainbowkit กันนะครับ ก่อนหน้านี้ผมเคยโพสบทความการทำปุ่ม Connect Wallet ง่ายๆ ไว้ตามโพสด้านล่างนี้ เนื้อหาบทความนี้ก็เป็นบทความอัพเดทนะครับ

โดย ผมพยายามอธิบายบ่างส่วนเพิ่มเติม รวมถึงอัพเดทตัว Library จากบทความที่แล้วที่ใช้ Rainbowkit v0.7.1 เป็นปัจจุบัน 0.12.x แล้ว (จริงๆ ก็ไม่มีอะไรเปลี่ยนแปลงมาก เพราะบทความเราแค่ connect wallet ไม่ได้ sign transaction หรือ call contract)
ข้อดีของ Rainbowkit
- ข้อแรก ผมว่ามันง่ายมาก ในการทำปุ่ม Connect Button ไม่กี่ขั้นตอนเท่านั้น
- UI ก็พร้อมใช้งานเลย มี handle ต่างๆ เช่น auto connect, refresh, ดู list transaction ดู balance ต่างๆ
- ปรับแต่ง chains เพิ่ม Wallets เองไม่ยาก (ใน Docs มีเขียนไว้หมดแล้ว)
มาลองสร้างโปรเจ็คกันดูครับ!
Step 1 - สร้างโปรเจ็ค
เริ่มแรก ทำการสร้างหน้าเว็บขึ้นมาก่อน เว็บเป็น React TypeScript ขึ้นโปรเจ็คด้วย Vite.js
npm create vite@latest hello-rainbowkit -- --template react-ts
ติดตั้ง wagmi, rainbowkit และ ethers.js v5
npm i @rainbow-me/rainbowkit wagmi ethers@5
Start server Vite.js
npm run dev
จะได้หน้าตาเริ่มต้นแบบนี้

ต่อมา ผมเพิ่มปุ่ม ConnectButton โดยการปรับ main.tsx
ให้ใช้ WagmiConfig
และ RainbowKitProvider
แบบนี้
ไฟล์ main.tsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import { WagmiConfig, configureChains, createClient } from 'wagmi'
import { mainnet, sepolia } from 'wagmi/chains'
import { publicProvider } from 'wagmi/providers/public'
import { getDefaultWallets, RainbowKitProvider } from '@rainbow-me/rainbowkit'
import '@rainbow-me/rainbowkit/styles.css'
import './index.css'
const { chains, provider } = configureChains(
[mainnet, sepolia],
[publicProvider()]
)
const { connectors } = getDefaultWallets({
appName: 'Hello RainbowKit',
chains,
})
const wagmiClient = createClient({
autoConnect: true,
connectors,
provider,
})
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<React.StrictMode>
<WagmiConfig client={wagmiClient}>
<RainbowKitProvider chains={chains}>
<App />
</RainbowKitProvider>
</WagmiConfig>
</React.StrictMode>
)
อธิบายจากโค๊ดด้านบน
- เริ่มต้น import css ของ rainbowkit ก่อน
import '@rainbow-me/rainbowkit/styles.css'
2. ทำการ config chains ที่จะมีให้เลือก และก็ Provider ที่เราต้องการ (ตัวอย่างใช้แค่ publicProvider ถ้าใครใช้ AlchemyProvider ก็สามารถเพิ่ม AlchemyProvider ได้
import { configureChains } from 'wagmi'
import { mainnet, sepolia } from 'wagmi/chains'
import { getDefaultWallets } from '@rainbow-me/rainbowkit'
const { chains, provider } = configureChains(
[mainnet, sepolia],
[publicProvider()]
)
const { connectors } = getDefaultWallets({
appName: 'Hello RainbowKit',
chains,
})
3. สร้าง wagmiClient โดยใช้ค่าจาก configureChains
import { createClient } from 'wagmi'
const wagmiClient = createClient({
autoConnect: true,
connectors,
provider,
})
4. สุดท้าย wrap RainbowKitProvider
กับ WagmiConfig
<WagmiConfig client={wagmiClient}>
<RainbowKitProvider chains={chains}>
<App />
</RainbowKitProvider>
</WagmiConfig>
ทีนี้เมื่อเรามี RainbowKitProvider เรียบร้อยแล้ว เราก็สามารถใช้งาน ConnectButton ได้ โดยที่มี wagmi
เป็น hooks เอาไว้จัดการเรื่อง connect, ดูข้อมูล balance, account, transactions อื่นๆ (จริงๆ ต้องบอกว่าส่วนใหญ่คือ wagmi มากกว่า ตัว RainbowKit เหมือนเป็น UI มาครอบอีกที)
Step 2 - เพิ่มปุ่ม Connect Button
ทีนี้ เราจะเพิ่มปุ่ม ConnectButton ก็คือต้องเปิดไฟล์ App.tsx
และทำการแก้ไข ไปแทนที่ read the docs ที่เป็น default ตอนสร้างโปรเจ็คด้วย Vite
import { ConnectButton } from '@rainbow-me/rainbowkit'
function App() {
return (
...
<p className="read-the-docs">
<ConnectButton />
</p>
)
}
เราก็จะได้ปุ่ม Connect Wallet แล้ว สามารถต่อ Metamask ได้ มี Popup เด้ง สวยงาม


สิ่งที่ต้องมี คือ ต้องติดตั้ง Metamask เป็น Extensions ก่อนนะครับ ไม่งั้น Popup ของ Rainbowkit จะไม่มีให้เลือก (ในตัวอย่างใช้ default ไม่ได้ custom wallet เอง)
Step 3 - Connect Contract
ขั้นตอนนี้ เราจะทำการ connect Contract เพื่อไปดึงข้อมูลนะครับ ตัวอย่าง ผมจะดึงข้อมูล จาก Mainnet (เนื่องจากแค่ read เลยไม่ต้องเสียอะไร) ตัวอย่างผมไปดึงเหรียญ USDT จริงๆ
เราจะใช้ wagmi hooks ชื่อ useContract
โดยต้องใช้ address
และ abi
ซึ่ง address หาได้จาก etherscan หรือ official ของ token นั้นๆ ส่วน abi ก็ใช้ default ERC20 ซึ่ง wagmi
มีให้
import { erc20ABI, useContract, useProvider } from 'wagmi'
const provider = useProvider()
const contract = useContract({
address: '0xdac17f958d2ee523a2206206994597c13d831ec7',
abi: erc20ABI,
signerOrProvider: provider,
})
ลองดึง totalSupply ก่อนเลย
const totalSupply = await contract.totalSupply()
ลองดึง balance ของ user
const balance = await contract.balanceOf('<WALLET_ADDRESS>')
ค่าที่ได้ ก็จะเป็น BigNumber เราก็เอามา formatUnits หรือแปลงให้เป็น number / string ก็แล้วแต่เราเนอะ
จริงๆ get balance ของ ERC20 ตัว wagmi ก็มี hooks เหมือนกัน ใช้อันนี้แทนได้
import { fetchBalance } from '@wagmi/core'
const balance = await fetchBalance({
address: '<WALLET_ADDRESS>',
token: '0xdac17f958d2ee523a2206206994597c13d831ec7',
})
เรื่องของ wagmi hooks ไว้บทความอื่นละกันนะครับ บทความนี้ขอเป็นตัวอย่างการทำ Connect Wallet ด้วย RainbowKit ก่อน
ไฟล์ Component ที่เอาไว้ดึงข้อมูล token มี useEffect เพื่ออ่านค่า contract และก็นำมา set state จากนั้น ก็ render ข้อมูล
import { useEffect, useState } from 'react'
import { ethers } from 'ethers'
import { erc20ABI, useContract, useProvider } from 'wagmi'
interface Token {
name: string
symbol: string
decimals: number
totalSupply: string
}
export default function TokenInfo() {
const [token, setToken] = useState<Token>({
name: '-',
symbol: '-',
decimals: 0,
totalSupply: '0',
})
const provider = useProvider()
const contract = useContract({
address: '0xdac17f958d2ee523a2206206994597c13d831ec7',
abi: erc20ABI,
signerOrProvider: provider,
})
useEffect(() => {
readContract()
}, [])
const readContract = async () => {
const symbol = (await contract?.symbol()) || '-'
const name = (await contract?.name()) || '-'
const decimals = (await contract?.decimals()) || 6
const ts = (await contract?.totalSupply()) || 0
const totalSupply = ethers.utils.formatUnits(ts, decimals)
setToken({
...token,
name,
symbol,
decimals,
totalSupply,
})
}
return (
<div>
<h2>Token Information</h2>
<p>Name: {token.name}</p>
<p>
Total Supply : {token.totalSupply} {token.symbol}
</p>
</div>
)
}
เพิ่ม Component <TokenInfo />
ที่ไฟล์ App.tsx
ก็จะได้ดังภาพครับ

หวังว่าบทความนี้จะเป็นไอเดีย เป็นแนวทางให้เพื่อนๆ นำไปประยุกต์ใช้งานกันดูนะครับ สุดท้าย Source Code เอาไปดูเพิ่มเติมครับ
Source Codeเผื่อ ใครสนใจเริ่มเขียน Solidity / Smart Contract สามารถอ่านบทความก่อนหน้านี้ของผมได้ เพิ่มเติมครับ


Happy Coding ❤️
Reference

