【DApp開発入門】MetaMaskを操作する
みなさんこんにちは!DApp開発入門と題してDApp開発の基礎中の基礎を理解していく記事を書いています!
前回は、Web3.jsを使って実際にブロックチェーンをやりとり (情報の取得)をしてみました。
前回の記事を読んでいただけると、「情報の取得」は容易にできるようになります。しかし、アプリケーションを構築する上で、もう一つ必要なことがあります。
それは、「情報の変更」です。
トークンの残高を知るには「情報の取得」でいいですが、トークンを人に渡したければ、自分の残高を減らし、相手の残高を増やす必要があります。
つまり、情報の変更が必要になるのです。
そして、そのためには基本的にMetaMask等のウォレットからブロックチェーンに変更の命令(トランザクション)を出さないといけないのです。
今回は、トランザクションを出すことができるようになるための準備として、MetaMaskを操作する方法を見ていこうと思っています。
(ウォレットアドレスと、接続しているチェーンのIDを取得しようと思います。)
では、早速始めていきましょう!
(MetaMaskがインストールされているブラウザでの動作を想定しています。
まだインストールされていないという人はこちらからどうぞ!)
React Appの作成
今回は、TypeScriptでMetaMaskを用いる際に注意しないといけないポイントも説明するために、ReactでTypeScriptを用いていきます。React Appを作っていきましょう。
npx create-react-app wallet-demo --template typescript
まずは、アカウントアドレスを取得するコードから書いていこうと思います。
アカウントアドレスの取得
const getAccount = async () => {
try {
const account = await window.ethereum.request({
method: "eth_requestAccounts",
});
if (account.length > 0) {
return account[0];
} else {
return "";
}
} catch (err) {
console.error(err);
return "";
}
};
以下のDocumentによると、windowオブジェクトはコードを実行しているウィンドウを表しています。ここではMetaMaskはブラウザの拡張機能として機能しているため、ここではwindowを通して扱います。window.ethereum.requestという関数で"eth_requestAccounts"というmethodを用いてアカウントアドレスを取得しています。
これを組み込めたら、冒頭のimport文にuseState(from "react")を追加して、App() 関数の中に以下のコードを追加してください。
const [currentAccount, setCurrentAccount] = useState("");
getAccount().then(setCurrentAccount);
この時点でのコードは下のようになります。
import React from "react";
import logo from "./logo.svg";
import "./App.css";
import { useState } from "react";
const getAccount = async () => {
try {
const account = await window.ethereum.request({
method: "eth_requestAccounts",
});
if (account.length > 0) {
return account[0];
} else {
return "";
}
} catch (err) {
console.error(err);
return "";
}
};
function App() {
const [currentAccount, setCurrentAccount] = useState("");
getAccount().then(setCurrentAccount);
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.tsx</code> and save to reload.
</p>
<p>wallet address: {currentAccount}</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;
これができたら、ターミナルでnpm startしてみてください。
ここが、私が今回TypeScriptをあえて用いた理由です。
みなさん、おそらくエラーが発生しているのでは無いでしょうか?
ここで問題になっているのはwindow.ethereumの部分かと思います。
TypeScriptは静的型付け言語であるため、コンパイルの時点でwindowオブジェクトにetherermというプロパティが存在することを示さなくてはいけません。(JavaScriptの場合は、実行時にetherermプロパティが存在すれば良いため、コンパイル時にエラーが発生することはありません。)
この問題の対処法として、以下の記事がとても参考になったのでご紹介いたします。(簡潔にまとまっていて、2分もあればエラーに対処できるので、参考にしつつwindow.d.jsファイルを追加し、編集してください!)
window.ethereumのエラーは解消されましたでしょうか?
では、もう一度ターミナルからnpm startしてください!
いかがでしょうか?下のように、MetaMaskのアドレスが表示されましたでしょうか?
これがうまくいったら、次はアカウントが接続しているチェーンのIDを取得していきましょう。
チェーンIDの取得
チェーンIDの取得は以下のようにして行います。
const getChainID = async () => {
const chainId = await window.ethereum.request({ method: "eth_chainId" });
return parseInt(chainId);
};
アカウントアドレスの取得と同様に、window.ethereum.requestメソッドを用いていることがわかっていただけますでしょうか?
ここで、parseInt() をchainIdに用いていることを疑問に思った人もいるかもしれません。実は、取得されるchainIdは16進数で表された文字列として返されます。(例えば、chainId 81のShibuya testnetの場合、"0x51")
なので、parseIntを用いてnumber型に直し、返しているという訳です。
では、App関数の中でgetChainID関数を呼び出し、chainIDをセットしてみましょう。
import React from "react";
import logo from "./logo.svg";
import "./App.css";
import { useState } from "react";
const getAccount = async () => {
try {
const account = await window.ethereum.request({
method: "eth_requestAccounts",
});
if (account.length > 0) {
return account[0];
} else {
return "";
}
} catch (err) {
console.error(err);
return "";
}
};
const getChainID = async () => {
const chainId = await window.ethereum.request({ method: "eth_chainId" });
return parseInt(chainId);
};
function App() {
const [currentAccount, setCurrentAccount] = useState<string>("");
const [chainId, setChainId] = useState<number>(0);
getAccount().then(setCurrentAccount);
getChainID().then(setChainId);
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.tsx</code> and save to reload.
</p>
<p>wallet address: {currentAccount}</p>
<p>chain ID: {chainId}</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;
React Appの画面にchain IDが追加されましたでしょうか?
これで無事に、アカウントアドレスとチェーンIDの取得に成功しました!
まとめ
みなさんいかがだったでしょうか?
今回はwindow.ethereum.requestメソッドを用いてMetaMaskからアカウントアドレスとチェーンIDを取得する方法を確認していきました。
これができれば基本的なMetaMaskからの情報の取得はOKだと思います。
なので、以降の記事ではどうやってフロントエンドからトランザクションを発生させるかという手順を紹介していきます。そのための1段階目として、次回の記事では今回学んだことを用いて、MetaMaskから署名を発行する方法について学んでいきたいと思います。楽しみにしていてください!