本文へスキップ
このページは英語からの機械翻訳を使用しており、誤りや不明瞭な表現が含まれている可能性があります。最も正確な情報については、オリジナルの英語版をご覧ください。頻繁な更新のため、一部のコンテンツはオリジナルの英語になっている可能性があります。Crowdinでの取り組みに参加して、このページの翻訳改善にご協力ください。 (Crowdin translation page, Contributing guide)

Web3ModalをdAppに統合する

はじめに

Web3Modalは、シンプルでカスタマイズ可能な設定で、開発者がdAppsに複数のプロバイダのサポートを追加するのを助ける、使いやすいライブラリです。 ウォレットの接続、取引の実行、アカウントの管理が簡単にできる。 ウォレットの接続、取引の実行、アカウントの管理が簡単にできる。

このガイドでは、web3Modalライブラリを使用して、Kaia Wallet、Klip、Metamask、Coinbase Walletなどの複数のウォレットをKaia Network上に構築したdAppに統合します。

前提条件

Web3Modalとウォレットプロバイダーのオプションを設定する

ステップ 1:Web3ModalとEthereumライブラリのインストール

このままでは、Web3Modalは、接続されたアカウントやネットワークデータを取得するようなイーサリアムのインタラクションのための組み込みサポートを提供していません。 ユーザーのアドレスや接続しているネットワークIDを読み取るには、イーサリアムライブラリから直接情報をリクエストする必要があることに注意してください。 このガイドでは、ethers.jsを使って情報を取得します。 このデータをフェッチして保存する1つの方法は、ユーザーをダップに接続するときだ。 web3Modalと、ブロックチェーンとやりとりするためのお好みのライブラリをインストールする。 このチュートリアルでは、Web3Modalから派生した@klaytn/web3modalをインストールし、Kaia WalletとKlip walletを追加するように修正します。 また、このチュートリアルでは、ethers.jsを使ってKaiaブロックチェーンとやりとりします。 また、このチュートリアルでは、ethers.jsを使ってKaiaブロックチェーンとやりとりします。


npm install @klaytn/web3modal
npm install --save ethers

ステップ 2:ウォレットプロバイダーオプションでWeb3Modalをインスタンス化する

お好みのウォレットプロバイダーをインストールしてください。 お好みのウォレットプロバイダーをインストールしてください。 ここでは、Kaia Wallet、Klip、Coinbaseのウォレットプロバイダーをインストールします。


npm install --save @coinbase/wallet-sdk
npm install --save @klaytn/kaikas-web3-provider
npm install --save @klaytn/klip-web3-provider

あなたのApp.jsファイルで、CoinbaseWalletSDK、KaikasWeb3Provider、KlipWeb3Providerをインポートし、あなたのdappと統合するための様々なプロバイダオプションをインスタンス化する。


import CoinbaseWalletSDK from '@coinbase/wallet-sdk';
import { KaikasWeb3Provider } from "@klaytn/kaikas-web3-provider";
import { KlipWeb3Provider } from "@klaytn/klip-web3-provider";
export const providerOptions = {
coinbasewallet: {
package: CoinbaseWalletSDK,
options: {
appName: "Web 3 Modal Demo",
infuraId: process.env.INFURA_KEY
}
},
walletconnect: {
package: WalletConnect,
options: {
infuraId: process.env.INFURA_KEY
}
}
};
const providerOptions = {
coinbasewallet: {
package: CoinbaseWalletSDK, // required
options: {
appName: "Web3Modal Kaia dApp", // required
infuraId: "NFURA_KEY", // required
rpc: "https://public-en.node.kaia.io", // Optional if `infuraId` is provided; otherwise it's required
chainId: 1001, // Optional. It defaults to 1 if not provided
darkMode: false // Optional. Use dark theme, defaults to false
}
},
klip: {
package: KlipWeb3Provider, //required
options: {
bappName: "Web3Modal Kaia dApp", //required
rpcUrl: "https://public-en.node.kaia.io" //required
}
},
kaikas: {
package: KaikasWeb3Provider // required
}
};

ステップ 3:web3modalをインスタンス化する

次に、プロバイダのオプションを渡してWeb3Modalをインスタンス化する。


import Web3Modal from "@klaytn/web3modal";
const web3Modal = new Web3Modal( {
cacheProvider: true,
providerOptions,
} )

ウォレット接続の確立

ユーザーのウォレットへの接続を確立するには、Web3Modal インスタンスで connect() メソッドを呼び出します。 この操作を非同期関数でラップし、取得したプロバイダーをステート内に保存して、アプリ全体で再利用することを推奨する。 この操作を非同期関数でラップし、取得したプロバイダーをステート内に保存して、アプリ全体で再利用することを推奨する。


import { ethers } from 'ethers';
import { useState } from 'react';
function App() {
const [provider, setProvider] = useState();
const connectWallet = async () => {
try {
const web3ModalProvider = await web3Modal.connect();
// this guide uses ethers version 6.3.0.
const ethersProvider = new ethers.BrowserProvider(web3ModalProvider);
// for ethers version below 6.3.0.
// const provider = new ethers.providers.Web3Provider(web3ModalProvider);
setProvider(web3ModalProvider);
} catch (error) {
console.error(error);
}
};
return (
<div className="App">
<button onClick={connectWallet}>Connect Wallet</button>
</div>
);
}

ユーティリティ機能の設定

このガイドでは、truncateAddress()toHex()といったutils関数を利用する。 truncateAddress()関数は有効なアドレスを受け取り、渡されたアドレスをより読みやすい形式で返す。 一方、toHex()`関数は数値を16進数に変換する。 以下のステップは、プロジェクトでutils関数をセットアップして使用する方法を示しています。 truncateAddress()関数は有効なアドレスを受け取り、渡されたアドレスをより読みやすい形式で返す。 一方、toHex()`関数は数値を16進数に変換する。 以下のステップは、プロジェクトでutils関数をセットアップして使用する方法を示しています。

ステップ 1:ルートフォルダ srcutils.js ファイルを作成する。

新しく作成したutils.jsファイルに以下のコードを貼り付ける。


export const truncateAddress = (address) => {
if (!address) return "No Account";
const match = address.match(
/^(0x[a-zA-Z0-9]{2})[a-zA-Z0-9]+([a-zA-Z0-9]{4})$/
);
if (!match) return address;
return `${match[1]}…${match[2]}`;
};
export const toHex = (num) => {
const val = Number(num);
return "0x" + val.toString(16);
};

ステップ 2:App.js\`ファイルに関数をインポートします。


import { truncateAddress, toHex } from "./utils";

接続、アカウント、ネットワーク情報へのアクセス

このままでは、Web3Modalは、接続されたアカウントやネットワークデータを取得するようなイーサリアムのインタラクションのための組み込みサポートを提供していません。 ユーザーのアドレスや接続しているネットワークIDを読み取るには、イーサリアムライブラリから直接情報をリクエストする必要があることに注意してください。 このガイドでは、ethers.jsを使って情報を取得します。 このデータをフェッチして保存する1つの方法は、ユーザーをダップに接続するときだ。


const [provider, setProvider] = useState();
const [account, setAccount] = useState();
const [chainId, setChainId] = useState();
const connectWallet = async () => {
try {
const web3ModalProvider = await web3Modal.connect();
// this guide uses ethers version 6.3.0.
const ethersProvider = new ethers.BrowserProvider(web3ModalProvider);
// for ethers version below 6.3.0.
// const provider = new ethers.providers.Web3Provider(web3ModalProvider);
const accounts = await ethersProvider.listAccounts();
const network = await ethersProvider.getNetwork();
setProvider(provider);
if (accounts) setAccount(accounts[0]);
setChainId(network.chainId.toString());
} catch (error) {
console.error(error);
}
};
return (
<div className="App">
<button onClick={connectWallet}>Connect Wallet</button>
<div>Connected To Chain ID: ${chainId}</div>
<div>Wallet Address: ${truncateAddress(account)}</div>
</div>
);

ウォレットの切断

ウォレットからの切断は web3Modal インスタンスの clearCachedProvider() メソッドを使用することで達成されます。 また、以前に保存された接続データをクリアするために、ステートをリフレッシュすることも良い習慣のひとつである。 また、以前に保存された接続データをクリアするために、ステートをリフレッシュすることも良い習慣のひとつである。


function App() {
const disconnect = async () => {
await web3Modal.clearCachedProvider();
refreshState();
};
// refresh state
const refreshState = () => {
setAccount();
setChainId();
// make sure to add every other state variable declared here.
}
return (
<div className="App">
<button onClick={disconnect}>Disconnect</button>
</div>
);
}

dAppのステートはユーザーが操作することで変化することを念頭に置いておくことが重要で、それに対応してリリースされるイベントをサブスクライブするのがベストプラクティスだ。 これらのイベントへのサブスクリプションを持つ useEffect フックを作成し、変更に適切に対応できるようにします。 これらのイベントへのサブスクリプションを持つ useEffect フックを作成し、変更に適切に対応できるようにします。


useEffect(() => {
if (provider?.on) {
const handleAccountsChanged = (accounts) => {
setAccount(accounts);
};
const handleChainChanged = (chainId) => {
setChainId(chainId);
};
const handleDisconnect = () => {
disconnect();
};
provider.on("accountsChanged", handleAccountsChanged);
provider.on("chainChanged", handleChainChanged);
provider.on("disconnect", handleDisconnect);
return () => {
if (provider.removeListener) {
provider.removeListener("accountsChanged", handleAccountsChanged);
provider.removeListener("chainChanged", handleChainChanged);
provider.removeListener("disconnect", handleDisconnect);
}
};
}
}, [provider]);

ネットワークの切り替えまたはカスタムネットワークの追加

先に述べたように、Web3Modalはイーサリアムとのやり取りをビルトインでサポートしていない。 ネットワークを追加または切り替えるには、イーサリアムライブラリに(EIP-3085またはEIP-3326を介して)直接リクエストする必要があります。 以下は、ネットワークの切り替えを要求し、ユーザーのウォレットにそのネットワークがまだ存在しない場合、フォールバックとしてそのネットワークを追加する例である:


const switchNetwork = async () => {
if (!provider) return;
try {
await provider.request({
method: "wallet_switchEthereumChain",
params: [{ chainId: toHex(8217) }],
});
} catch (switchError) {
// This error code indicates that the chain has not been added to MetaMask.
if (switchError.code === 4902) {
try {
await provider.request({
method: "wallet_addEthereumChain",
params: [
{
chainId: toHex(1001),
chainName: "Kairos Testnet",
rpcUrls: ["https://public-en-kairos.node.kaia.io"],
blockExplorerUrls: ["https://kairos.kaiascan.io/"],
},
],
});
} catch (addError) {
throw addError;
}
}
}
};
return (
<div className="App">
<button onClick={switchNetwork}>Switch Network</button>
</div>
)

メッセージに署名する

プロバイダーと署名者オブジェクトを初期化すると、ユーザーは任意の文字列に署名できる。


// add to the existing useState hook.
const [signedMessage, setSignedMessage] = useState("");
const signMessage = async(e) => {
e.preventDefault()
if (!provider) return;
try {
const signature = await provider.request({
method: "personal_sign",
params: [message, account]
});
setSignedMessage(signature);
} catch (error) {
console.log(error);
}
}
return (
<div className="App">
<form onSubmit={signMessage}>
<input type="text" name="message" placeholder="Set message" required/>
<input type="submit" value="Sign Message"/>
</form>
<div>SignedMessage: ${signedMessage}</div>
</div>
);

ネイティブ・トランザクションの送信

あるユーザーから別のユーザーへKAIAを送信するなど、ネイティブ・トランザクションを実行できる。


// add to the existing useState hook.
const [txHash, setTxHash] = useState();
const sendKaia = async () => {
if (!provider) return;
const destination = “paste recipient address”;
// this guide uses ethers version 6.3.0.
const ethersProvider = new ethers.BrowserProvider(provider);
// for ethers version below 6.3.0.
// const provider = new ethers.providers.Web3Provider(provider);
const signer = await ethersProvider.getSigner();
// Submit transaction to the blockchain and wait for it to be mined
const tx = await signer.sendTransaction({
to: destination,
value: ethers.parseEther("0.1"),
maxPriorityFeePerGas: "5000000000", // Max priority fee per gas
maxFeePerGas: "6000000000000", // Max fee per gas
})
const receipt = await tx.wait();
setTxHash(receipt.hash)
}
return (
<div className="App">
<button onClick={sendKlay}>Send Klay</button>
<div>Send-Kaia Tx Hash : {txHash ? <a href={`https://kairos.kaiascope.com/tx/${txHash}`} target="_blank">Kaiascope</a> : ' ' } </div>
</div>
);

スマートコントラクトとの連携

Web3Modalのプロバイダと署名者オブジェクトを使えば、ブロックチェーンにデプロイされたスマートコントラクトへの書き込みや、スマートコントラクトからの読み込みといったコントラクトのやり取りができる。

1. コントラクトへの書き込み


// add to existing useState hook
const [contractTx, setContractTx] = useState();
const writeToContract = async (e) => {
e.preventDefault();
if (!provider) return;
// this guide uses ethers version 6.3.0.
const ethersProvider = new ethers.BrowserProvider(provider);
// for ethers version below 6.3.0.
// const provider = new ethers.providers.Web3Provider(provider);
const signer = await ethersProvider.getSigner();
// Paste your contractABI
const contractABI = [
{
"inputs": [
{
"internalType": "uint256",
"name": "_initNum",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "retrieve",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "num",
"type": "uint256"
}
],
"name": "store",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]
// Paste your contract address
const contractAddress = "0x3b01E4025B428fFad9481a500BAc36396719092C";
const contract = new ethers.Contract(contractAddress, contractABI, signer);
const value = e.target.store_value.value;
// Send transaction to smart contract to update message
const tx = await contract.store(value);
// Wait for transaction to finish
const receipt = await tx.wait();
const result = receipt.hash;
setContractTx(result)
}
return (
<div className="App">
<form onSubmit={writeToContract}>
<input name="store_value" placeholder="Set contract value" required/>
<input type="submit" value="Store"/>
</form>
<div>Write-to-contract Tx Hash: ${contractTx}</div>
</div>
)

2. コントラクトを読む


// add to existing useState hook
const [contractMessage, setContractMessage] = useState();
const readFromContract = async () => {
if (!provider) {
console.log("provider not initialized yet");
return;
}
// this guide uses ethers version 6.3.0.
const ethersProvider = new ethers.BrowserProvider(provider);
// for ethers version below 6.3.0.
// const provider = new ethers.providers.Web3Provider(provider);
// paste your contract ABI
const contractABI = [
{
"inputs": [
{
"internalType": "uint256",
"name": "_initNum",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "retrieve",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "num",
"type": "uint256"
}
],
"name": "store",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]
// paste your contract address
const contractAddress = "0x3b01E4025B428fFad9481a500BAc36396719092C";
const contract = new ethers.Contract(contractAddress, contractABI, ethersProvider)
// Reading a message from the smart contract
const contractMessage = await contract.retrieve();
setContractMessage(contractMessage.toString())
}
return (
<div className="App">
<button onClick={readFromContract}>Read From Contract</button>
<div>Read-from-contract Message: ${contractMessage}</div>
</div>
)

トラブルシューティング

Node fs error, add browser {fs: false} to package.json


Node fs error, add browser {fs: false} to package.json

これはKlip-web3-providerをインストールしたときに発生します。 この問題を解決するには、以下の手順に従ってください: この問題を解決するには、以下の手順に従ってください:

ステップ 1:node_modulesフォルダを開いて移動します。 Kaia/klip-web3-providerフォルダを探し、以下のようにpackage.jsonファイルに移動します:

@klaytn/klip-web3-provider/node_modules/caver-js/packages/caver.ipfs/package.json

ステップ 2:以下のコードを@klaytn/klip-web3-provider/node_modules/caver-js/packages/caver.ipfs/package.jsonファイルに貼り付けます。


"browser": {
"fs": false
},

Polyfill node core module error


BREAKING CHANGES: webpack<5 used to include polyfills for node.js core modules by default.

このエラーは webpack バージョン 5 を使用している場合に発生します。 このバージョンでは、NodeJSポリフィルはデフォルトではサポートされなくなりました。 この問題を解決するには、このガイドを参照してください。 このバージョンでは、NodeJSポリフィルはデフォルトではサポートされなくなりました。 先に述べたように、Web3Modalはイーサリアムとのやり取りをビルトインでサポートしていない。 ネットワークを追加または切り替えるには、イーサリアムライブラリに(EIP-3085またはEIP-3326を介して)直接リクエストする必要があります。 以下は、ネットワークの切り替えを要求し、ユーザーのウォレットにそのネットワークがまだ存在しない場合、フォールバックとしてそのネットワークを追加する例である:

次のステップ

Web3Modalに関するより詳細なガイドについては、Web3Modal DocsWeb3Modal Githubリポジトリを参照してください。 また、このガイドのコードの完全な実装はGitHubにあります。 はじめに

ページを改善してください。