PancakeSwap「Frontend」のソースコードを見てみた
string greeting = "こんにちは、web3エンジニアのポコ太郎です。";
今回の記事では、PancakeSwapのGithubで公開されている「フロントエンド」のソースコードを見ていきます。
PancakeSwap(パンケーキスワップ)とは、BNB Chain上に構築されたDEX(Decentralized Exchanges/分散型取引所)の一つです。
01. ディレクトリ構成(apps/web/)
フロントエンドのソースコード pancake-frontend/apps/web にフォーカスをして見ていきたいと思います。
pancake-frontend/apps/web/
├ public/ ------------------- 静的ファイル置き場
├ src/ ---------------------- メインコード
├ .env.development ---------- 環境変数 (開発環境)
├ .env.example -------------- 環境変数 (テンプレ)
├ .env.production ----------- 環境変数 (本番環境)
├ .eslintrc ----------------- ESLint設定ファイル
├ .gitignore ---------------- バージョン管理設定ファイル
├ babel-test.config.json ---- Babel設定ファイル
├ jest.config.js ------------ Jest設定ファイル
├ jest.setup.js ------------- Jestセットアップファイル
├ next-env.d.ts ------------- Next.js設定ファイル
├ next.config.mjs ----------- Next.js設定ファイル
├ package.json -------------- パッケージ管理ファイル
├ sentry.client.config.js --- Sentry設定ファイル
├ sentry.properties --------- Sentry設定ファイル
├ sentry.server.config.js --- Sentry設定ファイル
└ tsconfig.json ------------- TypeScript設定ファイル
ディレクトリは、「public」「src」の2種類となっており、非常なシンプルな構成です。
使われているフレームワークは、「Next.js (React, TypeScript)」です。
DAppsの多くはReactで実装してされているため、web3エンジニアを目指されている方は「React」の業務経験をつけていくことをオススメします。
日本では「Vueが得意です!」というエンジニアが多いですが、現状、Vueに対応したweb3ライブラリが非常に少ないです。
そのため、VueはDAppsとの親和性は低く、Reactの方が仕事に繋がりやすい技術となります。
02. ディレクトリ構成 (src/)
続きまして、メインコードが実装されている pancake-frontend/apps/web のディレクトリ構成を見ていきます。
pancake-frontend/apps/web/src/
├ __tests__/
├ components/ ---------- コンポーネント
├ config/ -------------- 設定
├ contexts/ ------------ Context (useContext, useMemo, Redux)
├ hooks/ --------------- Hook
├ pages/ --------------- Page
├ state/ --------------- State
├ style/ --------------- Style (CSS)
├ utils/ --------------- Utility
├ views/ --------------- View (Pageのロジック)
├ Providers.tsx -------- Provider (Wagmi, NextJSなど)
├ global.d.ts ---------- 型定義 (グローバル)
├ index.tsx ------------ インデックス
├ middleware.ts -------- Middleware
├ react-app-env.d.ts --- 型定義設定
└ testUtils.tsx -------- Utility (テスト用)
ディレクトリ構成は、Next.jsに準拠しており、非常にシンプルな構成となっております。
03. Metamask接続機能の実装
ディレクトリ構成が確認できましたので、Metamask接続機能の実装を見ていきます。
Metamask接続をするためには「Connect Wallet」を押下します。
ボタンは以下に実装されています。
pancake-frontend/appfs/web/src/components/ConnectWalletButton.tsx
import { WalletModalV2 } from '@pancakeswap/ui-wallets'
中略
const handleActive = useActiveHandle()
const { login } = useAuth()
const {
t,
currentLanguage: { code },
} = useTranslation()
const { connectAsync } = useConnect()
const { chainId } = useActiveChainId()
const [open, setOpen] = useState(false)
const docLink = useMemo(() => getDocLink(code), [code])
const handleClick = () => {
if (typeof __NEZHA_BRIDGE__ !== 'undefined') {
handleActive()
} else {
setOpen(true)
}
}
const wallets = useMemo(() => createWallets(chainId, connectAsync), [chainId, connectAsync])
return (
<>
<Button onClick={handleClick} {...props}>
{children || <Trans>Connect Wallet</Trans>}
</Button>
<WalletModalV2
docText={t('Learn How to Connect')}
docLink={docLink}
isOpen={open}
wallets={wallets}
login={login}
onDismiss={() => setOpen(false)}
/>
</>
)
ウォレット接続時のUIは「@pancakeswap/ui-wallets」のWalletModalV2コンポーネントが使われており、ウォレット接続処理は「useAuth」のlogin関数が使われています。
WalletModalV2を表示させるとこのような感じになります。
「Metamaskボタン」を押下すると、ウォレット接続処理が実行されます。
useAuthは、以下に実装されています。
pancake-frontend/appfs/web/src/hooks/useAuth.tsx
// ウォレット接続のライブラリには「wagmi」を使用
import {
ConnectorNotFoundError,
SwitchChainError,
SwitchChainNotSupportedError,
useConnect,
useDisconnect,
useNetwork,
} from 'wagmi'
中略
const useAuth = () => {
const dispatch = useAppDispatch()
const { connectAsync, connectors } = useConnect()
const { chain } = useNetwork()
const { disconnectAsync } = useDisconnect()
const { chainId } = useActiveChainId()
const [, setSessionChainId] = useSessionChainId()
const { t } = useTranslation()
// WalletModalV2のPropsに指定しているlogin
const login = useCallback(
async (connectorID: ConnectorNames) => {
const findConnector = connectors.find((c) => c.id === connectorID)
try {
// connectAsyncで接続処理が実行されている
const connected = await connectAsync({ connector: findConnector, chainId })
if (!connected.chain.unsupported && connected.chain.id !== chainId) {
replaceBrowserHistory('chain', CHAIN_QUERY_NAME[connected.chain.id])
setSessionChainId(connected.chain.id)
}
} catch (error) {
if (error instanceof ConnectorNotFoundError) {
throw new WalletConnectorNotFoundError()
}
if (error instanceof SwitchChainNotSupportedError || error instanceof SwitchChainError) {
throw new WalletSwitchChainError(t('Unable to switch network. Please try it on your wallet'))
}
}
return undefined
},
[connectors, connectAsync, chainId, setSessionChainId, t],
)
}
省略
PancakeSwapのMetamask接続処理には「wagmi」というライブラリが使われていることが分かりました。
04. wagmiとは
「wagmi」とは、Metamaskなどのウォレット接続やEVM互換のコントラクトとやり取りなどができるReact Hooksのコレクションです。
長所
ウォレット、ENS、コントラクト、トランザクション、署名などを操作するための20以上のフックが準備されている
Metamask、WalletConnect、Coinbase Wallet、および、Injected用の組み込みウォレットのコネクタ
キャッシング、リクエストの重複排除、永続性の強化
マルチコールのサポート
TypeScript対応
ENS、Foundation、SushiSwapで使用されている
短所
他のライブラリと比べると、対応しているウォレットが少ない
05. まとめ
Next.js (React, TypeScript) でDAppsを開発していきたいというエンジニアは、一度ローカル環境で動かしてみることをオススメします。
Thirdweb、Maralis、web3AuthなどSaaSを組み合わせることで、より効率よく開発ができるようになると思います。
最後までお読みいただき、ありがとうございました。
株式会社RuckPlusでは、web3開発に興味のあるエンジニアを探しております。
ご連絡をお待ちしております!
この記事が気に入ったらサポートをしてみませんか?