特定のNFTアカウントのNFT所持数を取得する方法を解説第二章
はじめに
この記事はウォレットが保有する特定のNFTアカウントのNFT所持数の一覧を取得する方法を二章に分けて徹底解説します。NFT・ブロックチェーン・JavaScriptをあまり知らない初心者でも理解できるようにわかりやすく丁寧に説明していきます。まだ第一章をお読みで無い方は以下のリンクからお読みください。
参考サイトと開発環境
PCスペック
MacBook Pro Apple M1
フレームワーク
Next.js(react)
※reactはJavaScriptで作られたweb上にUIを作成するためのフレームワークです。
ライブラリ
react
web3.js
本題(第二章)
それでは早速第二章を進めていきましょう。この章ではサイトと連携したMetaMaskのアカウント情報からNFT保持数を取得することを目標にしていきます。
現状はMetaMaskとアカウントを接続してアドレスを取得するところまで実装できています。
イーサリアムブロックチェーン上のコントラクトとやり取りするにはweb3.jsのweb3.eth.Contractを使用します。
以下の公式Documentのリンクをクリックしましょう。
web3.eth.Contract
少し難しい内容ですが読み進めていきましょう。このページには「web3.eth.Contractはイーサリアムブロックチェーン上のスマートコントラクトのやり取り簡単にしてくれます。新しく生成したインスタンスにjson形式のインタフェースを渡すことで呼び出してくれます」と言った内容が書かれています。ここで記述方法を確認して見ましょう。new contractという場所を見てください。
ここには文法と関数内に設定できる引数、戻り値の説明がされています。新しくコントラストのオブジェクトを生成するにはnewをつけてインスタンスを生成する必要があり、引数にはjson形式のインタフェースとオプションを渡すことができます。
インタフェースについて解説をしましょう。インタフェースは二つの異なる機器やシステム、ハードウェアの間で情報のやり取りを行う際にルールや決まりごととしてあらかじめ設定しておいたものです。いわば規格というやつです。今回使用する規格はERC(Ethereum Request for Comments)という規格でイーサリアム上で発行できるトークンについての規格です。ERCには主要となるERC20をはじめ、発行された順番に数字がついています。私たちが使用する規格はERC721です。
ERC721ではNon-Fungible Token Standardという規約名になっています。つまりNFTに関する規約ですね。より詳しくこちらの規約を参照されたい方は以下のリンクをから参照してください。
ERC721 Non-Fungible Token Standard
ERC721の中にも沢山の機能がありますが私たちが今回使用したい機能はbalanceOfというメソッドです。ここではOpenZeppelinのDocumentを参考にします。
DocumentにはbalanceOfメソッドに調べたいオーナーのアカウントを渡すとトークン数が発行されると記載されています。
それでは実際にコードを書いていきましょう。
conponents/metamaskConnection.jsの中のconnectWallet関数の後に以下のコードを貼り付けてください。
const checkNFTOwnership = async (account) => {
// NFTコントラクトアドレスを設定
const nftContractAddress = '0x138A5C693279b6Cd82F48d4bEf563251Bc15ADcE';
// ERC721 ABIをインポートまたは定義
const erc721ABI = [
{
constant: true,
inputs: [{ internalType: 'address', name: 'owner', type: 'address' }],
name: 'balanceOf',
outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
payable: false,
stateMutability: 'view',
type: 'function',
},
];
const web3 = new Web3(window.ethereum);
const nftContract = new web3.eth.Contract(erc721ABI, nftContractAddress);
const balance = await nftContract.methods.balanceOf(account);
console.log(balance);
if (parseInt(balance) > 0) {
setIsConnected(true);
} else {
setIsConnected(false);
}
};
上から丁寧に説明していきます。
checkNFTOwnership関数名でaccountを引数にしてNFT保有数を取得する関数です。
まずはweb3.eth.Contractを使用するために調べたいNFTのコントラクトアドレス、ERC721のABI、Web3のインスタンスを記述します。以下のコードは先ほどのコードの一部になります。
// NFTコントラクトアドレスを設定
const nftContractAddress = '0x138A5C693279b6Cd82F48d4bEf563251Bc15ADcE';
// ERC721 ABIをインポートまたは定義
const erc721ABI = [
{
constant: true,
inputs: [{ internalType: 'address', name: 'owner', type: 'address' }],
name: 'balanceOf',
outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
payable: false,
stateMutability: 'view',
type: 'function',
},
];
const web3 = new Web3(window.ethereum);
nftContractAddressという変数名にCNP(CryptoNinja Partners)のコントラクトアドレスを文字列で挿入します。コントラクトアドレスの取得は以下のリンク内のContractから取得できます。
CNP(CryptoNinja Partners)のコントラクトアドレス
次にerc721ABIという変数名で必要な規約をとってきます。Git hub上にERC721の全ての機能のABIが公開されていますが、balanceOfメソッドの部分のみ抽出します。具体的には以下のリンクからソースコードを開き、以下の画像のRawボタンで全体を表示、写真の青線が引かれている部分をコピーして変数に格納してください。
ERC721-ABI.json
新しく関数を定義したので関数内で新しくWeb3インスタンスを生成する必要があり、new Web3で生成しています。
少しおさらいをしましょう。web3のContract関数を使うことでイーサリアムのブロックチェーンとやり取りができると先ほど紹介しました。そのコードの書き方をもう一度見ましょう。
引数にjson形式のインタフェースとアドレスを渡すことでインスタンスを生成できましたね。
const nftContract = new web3.eth.Contract(erc721ABI, nftContractAddress);
const balance = await nftContract.methods.balanceOf(account);
console.log(balance);
一行目では作成した二つの変数erc721ABIとnftContractAddressを渡そてnewで生成しています。生成したインスタンス内には様々な情報が格納されていますが、今回はbalanceOfを使います。二行目のようにbalanceOfに引数としてaccountを代入することでトークン数を取得することができます。
これでweb3を使った全ての機能を実現することができました。
最後に、コード全体を見ましょう。
// components/ConnectWallet.js
import React, { useState } from 'react';
import Web3 from 'web3';
import { toChecksumAddress } from 'ethereumjs-util';
const MetaMaskConnection = () => {
const [isConnected, setIsConnected] = useState(false);
const connectWallet = async () => {
if (window.ethereum) {
try {
await window.ethereum.request({ method: 'eth_requestAccounts' });
const web3 = new Web3(window.ethereum);
const accounts = await web3.eth.getAccounts();
const account = accounts[0]
checkNFTOwnership(account);
} catch (error) {
console.error('Error connecting to Metamask:', error);
}
} else {
alert('Please install Metamask to use this feature.');
}
};
const checkNFTOwnership = async (account) => {
// NFTコントラクトアドレスを設定
const nftContractAddress = '0x138A5C693279b6Cd82F48d4bEf563251Bc15ADcE';
// ERC721 ABIをインポートまたは定義
const erc721ABI = [
{
constant: true,
inputs: [{ internalType: 'address', name: 'owner', type: 'address' }],
name: 'balanceOf',
outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
payable: false,
stateMutability: 'view',
type: 'function',
},
];
const web3 = new Web3(window.ethereum);
const nftContract = new web3.eth.Contract(erc721ABI, nftContractAddress);
const balance = await nftContract.methods.balanceOf(account).call();
console.log(balance);
if (parseInt(balance) > 0) {
setIsConnected(true);
} else {
setIsConnected(false);
}
};
return (
<div>
<button onClick={connectWallet}>
{isConnected ? 'Connected' : 'Connect Wallet'}
</button>
</div>
);
};
export default MetaMaskConnection;
ここまでで動作がうまくいってない方はnpmでインストールしたいくつかのライブラリがうまく読み込めていなかったり、コードの記述に誤りがある可能性があります。コードの全体像は以下のgit hubで公開しておきますので参照してください。最低限必要なファイルのみアップしていますので、各々のnext.jsアプリに組み込んで試してください。
https://github.com/Tucker925H/NFT_connection_num_of_nft
コードを見ると今まで見たことないような部分もいくつかありますが、順に説明します。まずはreturn文の中を注目してください。return文の中にはJSXが記載されておりonClickメソッドでconnectWallet関数呼び出しています。connectWallet関数内にではwindow.ethereum、web3を使ってMetaMask認証を行い、取得したアドレスをaccountという変数に格納します。そのaccountをcheckNFTOwnership関数の引数に渡しています。checkNFTOwnership内ではNFTContractアドレスとABIを使って特定のNFTアカウントのNFT所持数を取得しています。balanceに1以上の数字が入っている場合はTrueを、そうでない場合はFalseをIsCountedに格納しreturn文の中で三項演算子として表示する値を変更しています。IsCountedはuseStateで宣言されているため関数が実行されるたびに値を変更し保持するようになっています。またbalanceOf()の後に.call()と記載されていますが、これはbalanceOf()で取得したオブジェクトのNFT数だけを取得するようにした記述です。気になる方はconsole.logで確認して見てください。
まとめ
二章にわたってNFT認証サイトの構築を行ってきました。ReactやNext.jsの説明などしきれなかった箇所があり、わかりにくいと感じた方もおられるかもしれませんが、公式ドキュメントで開発をするフローやWeb3技術でできることのイメージが湧けば幸いです。これからもNFTやWeb3に関する技術や情報を発信していきますのでよろしくお願いいたします。