Dev Protocol HandsOn - ログインと所持DEV表示

Kawakami
所要時間, 9分
初級

Metamaskに接続して認証を行い、ユーザーのウォレットアドレスと所持DEVを表示する permalink

はじめに今回作成する完成品を紹介します。

または以下のURLにアクセスしてください
https://9hnhu.csb.app/

このアプリケーションは、Metamaskに接続して認証を行い、ユーザーのウォレットアドレスと所持DEVを表示するアプリケーションになっています。

【動作説明】

  • Walletボタンを押すとMetamaskに接続処理が走ります
  • Metamaskがなかったり、Ropsten環境が設定されていない場合にエラーになります
  • Metamaskと正常に接続できるとログイン完了となります
  • ログインが完了するとあなたのウォレットアドレスと、所持DEV数が表示されます

それではハンズオンに入ります。 permalink

以下のURLにアクセスしてCodesandboxを開いてください。
https://codesandbox.io/s/login-with-wallet-build-qknzh

左側のExploreからsrc/index.tsを選択して、ソースコードを表示させてください。

最下部までスクロールすると、①があります。
これから①〜⑨までをコーディングしていきます。

①:ここでは、ボタンのクリックイベントとclickLoginButtonメソッドの紐づと、ボタン押された際の処理のコードが書かれています。

②:上部にスクロールして②を見つけてください。clickLoginButtonメソッドは、Metamaskにアクセスして認証処理を行い、ユーザーのウォレットアドレスと所持DEVを表示する。までを行っているメソッドです。

③:③から⑦にかけて、Metamaskの状態を判断してログイン済みかを判断します。Metamaskの状態として以下を定義しています

ログイン判定Metamaskの状態説明
未ログインMetamaskが未インストール状態ブラウザにMetamaskが搭載されていない状態
未ログインMetamaskと未接続状態MetamaskでWebサイトが接続許可できていない状態
未ログインMetamaskで未ログイン状態Metamask上でログインがされていない状態
未ログインMetamaskの接続ネットワークが違う状態Metamaskが接続しているネットワークがWebサイトが期待しているネットワークと違っている
ログイン上記の状態に当てはまっていないMetamaskからウォレットアドレスが取得できて、Webサイトが期待しているネットワークに接続が行えている状態

③では「Metamaskが未インストール状態」を判定します。スクロールして、isMetamask関数を見つけます。isMetamask関数を以下のようにコーディングします。

function isMetamask(): boolean {
return !!window.ethereum && !!window.ethereum.isMetaMask;
}

wen3.jsがインストールされると、windowオブジェクトにethereumが追加されます。ethereumにはisMetamask関数があり「Metamaskが未インストール状態」を判定できます。

④:次に「Metamaskと未接続状態」を判定します。スクロールしてconnectMetaMask関数を見つけます。connectMetaMask関数を以下のようにコーディングします。

async function connectMetaMask(): Promise<boolean> {
try {
await window.ethereum.request({ method: "eth_requestAccounts" });
} catch (e) {
if (e.code === 4001) {
return false;
}
}
return true;
}

「Metamaskと未接続状態」を判定するには、Metamaskからイーサリアムのアドレスを問い合わせます。その際にユーザーがMetamaskで接続拒否するなどWebサイトとMetamaskの接続が確立できていない場合に4001コードのエラーを返すのでこれを利用して判定します。
参考:https://docs.metamask.io/guide/rpc-api.html#permissions

⑤:次に「Metamaskで未ログイン状態」を判定します。スクロールしてisMetaMaskLogin関数を見つけます。isMetaMaskLogin関数を以下のようにコーディングします。

async function isMetaMaskLogin(): Promise<boolean> {
return !!(await getAccount());
}

isMetaMaskLogin関数では、getAccount関数を呼んでいます。getAccount関数ではMetamaskからウォレットアドレスを取得して返しています。
getAccount関数を以下のようにコーディングします。

async function getAccount() {
const accounts = (await window.ethereum.request({
method: "eth_accounts"
})) as string[];

return accounts[0];
}

⑥:次に「Metamaskの接続ネットワークが違う状態」を判定します。スクロールしてisMainNet関数を見つけます。isRopsten関数を以下のようにコーディングします。

function isRopsten() {
return parseInt(window.ethereum.chainId) === 3;
}

window.ethereum.chainIdでは、接続しているネットワークによって以下のCHAIN_IDを返します

ネットワーク名CHAIN_ID説明
Mainnet1Ethereum 本番環境ネットワーク
Ropsten3Ethereum テストネットワーク (PoW)
Rinkeby4Ethereum テストネットワーク (PoA)

参考:https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md

⑦:スクロールして⑦を見つけてください。⑦では、③から⑥までのチェックで引っかからない場合を「ログイン済み状態」としています。この後は、ログイン後の処理をコーディングしていきます。

⑧:ユーザーのウォレットアドレスを取得して表示させます。スクロールして⑧を探して以下のようにコーディングします。

  const walletAddress = await getAccount();
const addressElement = document.getElementById("address");
addressElement.innerText = walletAddress;

ウォレットアドレスを取得するのに⑤で作成したgetAccount関数を使っています。

⑨:次に、ユーザーの所持DEVを取得して表示させます。スクロールしてgetBalanceOfDEV関数をみつけます。getBalanceOfDEV関数を以下のようにコーディングします。

import { addresses, contractFactory } from "@devprotocol/dev-kit";
import { BigNumber } from "@ethersproject/bignumber";
import Web3 from "web3";

async function getBalanceOfDEV(walletAddress: string) {
const provider = new Web3(window.ethereum);
const client = contractFactory(provider.currentProvider);

const registryContract = client.registry(addresses.eth.ropsten.registry);

const addressDEV = await registryContract.token();

const amountBigNumber = BigNumber.from(
await client.dev(addressDEV).balanceOf(walletAddress)
);

const amount = amountBigNumber.div("1000000000000000000").toString();
return amount
}

getBalanceOfDEVを呼び出すときはawaitを追記してください

contractFactoryは、@devprotocol/dev-kitで宣言されている関数で、Web3currentProviderを引数に渡すことでclientを作成することができます。このclientを利用してDevProtocolを操作することができます。

ここからはclientを利用して所持DEV数を取得しています。

const registryContract = client.registry(addresses.eth.ropsten.registry);

Dev Protocolのコントラクトは種類ごとに分散されており、それぞれのコントラクトのアドレスはregistryContractで管理されています。上記の部分では、ropsten 環境のregistryContractを取得しています。DevProtocolでは、mainropstenの環境があります。

const addressDEV = await registryContract.token();

このハンズオンでは、所持DEV数を表示させたいので、DEVトークンを扱っているtokenコントラクトのアドレスを返しています。
Etherscanでコントラクトを見ることもできます。

  const amountBigNumber = BigNumber.from(
await client.dev(addressDEV).balanceOf(walletAddress)
);

dev関数はDEVトークンに関連するコントラクトのためのメソッドです。dev関数にDEVトークンのコントラクトアドレスを設定し、balanceOfメソッドに対象者のウォレットアドレスを指定することで、対象者の所持DEV数が返ってきます


clientにはdev関数の他にも以下の関数があります。

export type DevkitContract = {
readonly allocator: ReturnType<typeof createAllocatorContract>
readonly market: ReturnType<typeof createMarketContract>
readonly property: ReturnType<typeof createPropertyContract>
readonly propertyFactory: ReturnType<typeof createPropertyFactoryContract>
readonly lockup: ReturnType<typeof createLockupContract>
readonly withdraw: ReturnType<typeof createWithdrawContract>
readonly dev: ReturnType<typeof createDevContract>
readonly registry: ReturnType<typeof createRegistryContract>
readonly policy: ReturnType<typeof createPolicyContract>
readonly policyGroup: ReturnType<typeof createPolicyGroupContract>
readonly metrics: ReturnType<typeof createMetricsContract>
readonly policyFactory: ReturnType<typeof createPolicyFactoryContract>
}

コードベース:https://github.com/dev-protocol/dev-kit-js/blob/372c762539855b794af2e3df5774061d640f61d0/lib/contract.ts

また、dev関数にはbalanceOf関数の他にも以下の関数があります

export type DevContract = {
readonly totalSupply: () => Promise<string>
readonly balanceOf: (address: string) => Promise<string>
readonly transfer: (to: string, value: string) => Promise<boolean>
readonly allowance: (from: string, to: string) => Promise<string>
readonly approve: (to: string, value: string) => Promise<boolean>
readonly transferFrom: (
from: string,
to: string,
value: string
) => Promise<boolean>
readonly name: () => Promise<string>
readonly symbol: () => Promise<string>
readonly decimals: () => Promise<string>
readonly deposit: (to: string, value: string) => Promise<boolean>
readonly contract: () => Contract
}

コードベース:https://github.com/dev-protocol/dev-kit-js/blob/372c762539855b794af2e3df5774061d640f61d0/lib/dev/index.ts


const amount = amountBigNumber.div("1000000000000000000").toString();

ERC20トークンの小数点以下は18桁なので、小数点を合わせるために割っています。

以上でコーディングは終了となります。動作確認をしてみましょう。
ログインが行えて、自分のウォレットアドレスと所持DEV数が画面に表示されたら完了です。

🌈 この記事はお役に立ちましたか?

今後より良いコンテンツをお届けしていくために、ぜひご質問やフィードバックなどいただけると幸いです🌱
フォーラムはこちら

- Dev Protocol は全てOSSとして公開しています。ぜひIssueやPRを送ってください📢 時にバウンティがあります。
Dev ProtocolのGitHubはこちら

- Dev Protocol の改善提案(DIP)プロセスも公開されています。ぜひコメントをお待ちしています🌟
DIPはこちら