見出し画像

NFT所有者をToken IDごとに取得する

この記事では、NFTのIDごとに所有者に特典を配布したい等の目的で、
「ID: 所有アドレス」
のリストを取得する方法を2パターン、解説していきます。
もし、もっと良い方法があるよ!という方がいらっしゃればぜひ、ご教示いただけますと非常にありがたいです!
では、早速説明していこうと思います。

パターン1:node.jsのプロジェクトから取得

今回は、簡単に扱っていただくため、以下のGitリポジトリからTypeScriptのプログラムをcloneしていただき、動かしていきます。

コンソールを起動し、以下のコードを実行してください。

git clone https://github.com/Zac-eng/token_holder_getter.git
cd token_holder_getter
npm i

この状態で、以下のコマンドを打つと、結果が返ってくると思います。

ts-node main.ts

いかがでしょう。以下のような結果が返ってきていますでしょうか?

ここで、.envファイルに入っているRPCアドレスコントラクトアドレスを変更すると、ご自身のNFTコントラクトでも同様の操作が可能かと思います。
(ここで、デフォルトではzkatana networkと、その上に私がデプロイしたコントラクトのアドレスを用いています。)

これがどのような動作になっているかを以下の図に簡単にまとめたいと思います。次に紹介するパターン2と比べて理解してもらえると、スマートコントラクトに関する理解向上にもつながるかと思います!

パターン2:コントラクト内にリストを格納

こちらのパターンはRemixIDE上で完結します。
まず、以下のスマートコントラクトコードをRemixIDEに入力してください。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts@5.0.1/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts@5.0.1/access/Ownable.sol";

contract MyToken is ERC721, Ownable {
    uint256 private _nextTokenId;
    address[] public tokenHolders;

    constructor(address initialOwner)
        ERC721("MyToken", "MTK")
        Ownable(initialOwner)
    {}

    function safeMint(address to) public onlyOwner {
        uint256 tokenId = _nextTokenId++;
        tokenHolders.push(to);
        _safeMint(to, tokenId);
    }

    function getTokenHolders() public view returns (address[] memory) {
        return tokenHolders;
    }
}

ここでは、Remix VMの上でテストしていきます。

Remix VMではアカウントもRemix内のものなので、左のサイドバーにある"ACCOUNT"のところから操作します。
この実装では、NFTをミントする際に、コントラクト内に保存されているtokenHoldersというリストにそのアドレスがどんどん追加されていきます。そして、getTokenHoldersという関数を呼び出すとその中身が返ってくるという構造です。さまざまなアドレスに対してsafeMintを実行後、getTokenHoldersを呼び出してみてください。以下のような結果が得られましたでしょうか?(safeMintはownerからしか実行できないので、コントラクトをデプロイしたアドレスから実行してください。)

こちらの構造を図で表すと以下のようになります。

まとめ

パターン1:
ERC721のownerOf関数を取得したいIDの数だけ呼び出し、アドレスをTypeScriptのプログラム内で格納する方法
・コントラクトは単純になる。(メリット)
・RPCの呼び出し回数が増える。(デメリット)

パターン2:

スマートコントラクト内でaddressのリストを格納し、それを呼び出す関数を作成、呼び出しする方法
・一度のRPCでリストを取得することができる(メリット)
・コントラクトのデータ量が増え、ガス代が増加する。(デメリット)

より良い実装方法やご意見は連携しているX等でいただけますと幸いです!

この記事が気に入ったらサポートをしてみませんか?