ERC721の拡張機能である『ERC721A』について理解しよう！

# はじめに

初めまして。
**CryptoGames**というブロックチェーンゲーム企業でエンジニアをしている **cardene（かるでね）** です！
スマートコントラクトを書いたり、フロントエンド・バックエンド・インフラと幅広く触れています。

https://cryptogames.co.jp/

代表的なゲームは**クリプトスペルズ**というブロックチェーンゲームです。

https://cryptospells.jp/

今回は`ERC721A`についてまとめていきます。
以前勉強会をした時に使用した資料をもとに解説していきます。

勉強会と使用したスライドは以下になります。

https://cryptogames.connpass.com/event/273086/

https://speakerdeck.com/cardene/fei-enziniademoli-jie-dekiruyounierc721awowakariyasukujie-shuo

勉強会の動画もあります。

https://www.youtube.com/watch?v=U7QNVSwtU7M

# 概要

`ERC721A`は名前の通り`ERC721`の拡張機能です。

::: note info
`ERC721`については以下を参考にしてください！
:::

https://chaldene.net/erc721

::: note info
また、`ERC721A`についてより詳しく知りたい人は以下の記事を参考にしてください。
:::

https://chaldene.net/erc721a

# ERC20とERC721の違い

![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/12cce2cb-a469-9835-e9ed-7513ecfa8f32.png)

まずは`ERC20`と`ERC721`の違いを説明しています。

![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/e03477b2-ff9a-84b8-327b-944c73b74826.png)

簡単に違いを挙げるとすると、以下になります。

**ERC20**
トークン同士に違いはないため交換できる。
例）お金

**ERC721**
トークン同士に違いがあるため交換できない。
例）アート作品

::: note info
`ERC20`については以下を参考にしてください。
:::

https://chaldene.net/erc20

![9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/02b88ff0-3e4f-1ffe-4675-c86d70ff4f9e.png)

もう少し詳しく説明すると、`ERC721`はそれぞれユニークなトークンIDというものを持っています。
そのためそれぞれトークンIDが異なるため、同じ価値として交換ができないということです。

![10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/8280d514-3011-ee28-4b29-51cfad1f91b0.png)

他の説明として、`ERC20`トークンは「**誰がいくつ持っているか**」、`ERC721`は「**誰が何を持っているか**」という違いがあります。
これは、`ERC20`トークンは代替性（交換できる）があり、`ERC721`は非代替性（交換できない）という特徴による説明です。

# ERC721Enumerable

`ERC721`の拡張機能である、`ERC721Enumerable`の説明をしています。

![18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/12528d55-66cd-4dbb-9eb2-cf7ebb8af9f1.png)
![21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/8f9cb6da-9897-d9a5-ae14-4e62279f29bb.png)
![22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/0284f6cd-16f7-486c-367a-81d9513e73b0.png)

`ERC721Enumerable`を簡単に説明すると、「**あるアドレスが所有しているNFTの一覧を取得できる、`ERC721`の拡張機能。ただ、ガス代が高い...**」となります。
`ERC721`規格だとあるアドレスがどのNFTを所有しているかの一覧を取得することはできません。
一方、`ERC721Enumerable`を使用することで、あるアドレスがどのNFTを所有しているかの一覧を取得できるようになります。
しかし、その代償で一部の機能を実行する際にガス代が多くかかってしまいます...。

![23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/123e614c-945f-404a-d5d4-58fcfad3d6cf.png)

`ERC721Enumerable`には、上記の2つの課題があります。

**更新するデータが多い**
あるアドレスがどのNFTを所有しているかの一覧を取得ために、1つの動作ごとに書き換えるデータが多くなってしまいます。

**ガス代が高い**
課題1つ目に直結する部分ですが、書き換えるデータが多くなる分ガス代がより多くかかってしまいます。

![24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/a7afd21e-3e96-41fe-32b7-47637de547fb.png)

では実際どのようなデータを更新しているのでしょうか？
NFTのMint（発行）時には以下の3つのデータを更新しています。

1. Mint（発行）されているトークンの総量がいくつか？
2. あるアドレスが幾つのトークンを持っているか？
3. どのアドレスがどのトークンを所有しているか？

2と3は`ERC721`規格では存在しないデータであり、更新処理が結構手間なのでガス代が多くかかってしまいます。

![25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/941b191d-b0f8-4e95-842b-6cb945b46e6b.png)

ではここで、`ERC721Enumerable`の処理を図を用いて説明します。
画像のように3つのNFTをMintしようとしています。
青枠内の数字が「**Mintされているトークン総量**」で、白枠内の数字が「**アドレスが所有するトークン量**」です。
Mintのたびに更新されているのが確認できます。

![26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/29319256-aeae-c982-c570-8df70e444af2.png)

Mintのたびに更新されるということは、その都度ガス代がかかるということです。

![27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/8912b23f-358d-1c13-ddf9-478b0d095109.png)

ここで以下のような疑問が浮かびます。
「**Mint処理をまとめてしまってガス代を1度だけかかるようにすれば良くね？**」
ちまちま数字を更新するのではなく、一気に更新してしまおうという発想です。

# ERC721Aとは

この章では`ERC721A`の説明をしています。

![30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/5189190a-833c-ce8b-66fd-9fcacfeef6fd.png)

`ERC721A`を簡単に説明すると上記になります。
`ERC721Enumerable`との違いは「**ガス代を節約できる**」点です。

![31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/f88b15f2-f852-7e4f-8607-68e1357f9425.png)

実は`ERC721A`はNFTプロジェクトである「**[Azuki](https://www.azuki.com/)**」から提案された独自実装になります（「**[Azuki](https://www.azuki.com/)**」の「**A**」？）。
`ERC721Enumerable`を使用していたときは、トークンを1つ1つMintする必要があり、その度にトランザクションが発生していました。
一方、`ERC721A`を使用すると一度のトランザクションで、複数のNFTをMintすることができます。
これによりガス代が節約できます。
ジェネラティブNFTなど、連続したトークンIDのNFTを1つのアドレスでMintすることがある場合に役立ちます。

![34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/b4d1f02e-b967-3a87-d78b-4fa7106a37e9.png)

上図は、`ERC721Enumerable`と`ERC721A`のガス代の比較表です。
MintするNFTが増加するにつれてガス代の価格の比率が広がっていることが確認できます。

# ERC721Aの仕組み

では、`ERC721A`がどのような仕組みになっているか確認していきましょう。

## NFTに紐づいているアドレス

![35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/2712f47e-9aa3-b85f-e26e-a3b055fab8ed.png)

ERC721の場合、1つのNFT（トークンID）に対して所有しているアドレスが1対1で紐づきます。

![36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/4448f968-4baa-9c68-f7a6-73de086e926f.png)

一方、`ERC721A`だと、トークンIDが連続している場合所有しているアドレスは一部しか紐づきません。

![37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/d831097d-8a00-7e08-e5f4-7ee06c393663.png)

図を見ていただくとわかりますが、「**0xA...**」というアドレスがトークンIDの`1`~`5`を所有していますが、その一番若い数字のトークンIDしか紐づいていません。
これがガス代を節約している仕組みです。
ERC721の場合は5回データを書き換える必要がありますが、`ERC721A`の場合は1回で済んでしまいます。
（もちろんトークンIDが連続していない場合は1つずつデータを記録する必要があります）

## アドレスが所有しているNFTの一覧取得

では、あるアドレスが所有しているNFTの一覧の取得はどのように実行しているのでしょうか？

![38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/101c9196-eb8a-4cb6-6dce-6a14060e33f8.png)

やり方はシンプルで、先頭から1つずつ確認していき、該当するアドレスが出現したときにそのトークンIDを取得しています。
このとき、図のようにトークンID`2`はどのアドレスにも直接紐づいていないですが、直近で紐づいているアドレスが「**0xA...**」のため、所有者は「**0xA...**」であることがわかります。
トークンID`6`もこれと同じようにして、どのアドレスが所有者かわかります。

## 所有者の変更

NFTを販売したり、他のアドレスに送ったときどのように変更されるのか見ていきましょう！

![39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/ef4d6003-98fe-059f-02e7-e43ea35434c0.png)

まずは、図のようにトークンID`3`のNFTを「**0xA...**」から「**0xC...**」に送ります。
これで完了！

![40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/c348c423-58c8-f7fe-1a18-dc8a010c909e.png)

とはいかないです...。
なぜならトークンID`4`と`5`はどのアドレスにも直接紐づいていません。
そのため、トークンID`3`の所有者のアドレスを参照してしまい、トークンID`4`と`5`の所有者も「**0xC...**」となってしまいます。

![41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/e38c9ace-ed34-105e-686a-f94f3b28376f.png)

これを避けるために、トークンID`3`の所有者のアドレスを変更したのち、トークンID`4`を「**0xA...**」に紐づける必要があります。
これで更新は完了です！

# まとめ
最後にまとめていきます。
![42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/07551c37-e291-7b2b-8b2d-1b44a43ff28e.png)

`ERC721A`はあるアドレスが所有しているNFTの一覧を取得することができます。
また、複数のNFTを一度にMintでき、ガス代の節約ができます。
個人的な感想としては、`ERC721Enumerable`はデータの読み込みのコストを削減し、`ERC721A`はデータの書き込みのコストを削減していると思いました。
`ERC721Enumerable`は配列として、「**誰がどのトークンID**」を所有しているかというデータを持っているため、読み込み速度は速いです（配列から取得すれば良いため）。
しかし、その分データの書き込みが頻繁に発生してしまいます。
一方、`ERC721A`はデータの書き込み頻度を下げることでガス代の節約の実現ができています。
しかし、「**誰がどのトークンID**」を所有しているか確認するために、全てのトークンIDを確認する必要があります。
これはトークンIDの数にもよりますが、若干時間がかかります。
`ERC721A`は読み込みに時間がかかってもガス代は発生しないため、やはり`ERC721A`の方を使用する方がメリットが多いように感じています。

# 最後に

今回は`ERC721A`についてまとめてきました。
実装については今後追記していきます。
いかがだったでしょうか？
質問などがある方は以下のTwitterのDMなどからお気軽に質問してください！

[Twitter @cardene777](https://twitter.com/cardene777)

# 採用強化中！

CryptoGamesでは一緒に働く仲間を大募集中です。

https://www.wantedly.com/companies/cryptogames

この記事で書いた自分の経験からもわかるように、裁量権を持って働くことができて一気に成長できる環境です。
「ブロックチェーンやWeb3、NFTに興味がある」、「スマートコントラクトの開発に携わりたい」など、少しでも興味を持っている方はまずはお話ししましょう！