ERC721の拡張機能をざっくり仕組みから理解しよう！

# はじめに

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

https://cryptogames.co.jp/

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

https://cryptospells.jp/

今回は、OpenZeppelinで実装されている**ERC721**の拡張機能についてまとめた記事と、勉強会での発表資料をもとに簡単にまとめていきたいと思います。

勉強会の概要とアーカイブは以下に記載してあります。

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

発表で使用したスライドと発表内容を詳しく記載している記事は以下になります。

https://speakerdeck.com/cardene/erc721kuo-zhang-ji-neng-noshi-zu-miwoli-jie-siyou

https://chaldene.net/erc721-extension

# OpenZeppelinとは？

![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/1756fd3c-df11-67de-5fe2-3d783547aafb.png)

まずはOpenZeppelinとは何かから確認していきましょう。
OpenZeppelinとは、「**安全にスマートコントラクトを開発するためのライブラリ**」のことです。
OpenZeppelinを使用することで、開発者は1からスマートコントラクトを書く必要がなくなり、開発効率を向上させることができます。
また、多くのNFTやERC20トークンのコントラクトで使用されています。

# ERC721拡張機能

![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/b8ccb645-9cb6-5e80-400d-092238051cec.png)

今回発表するERC721拡張機能は上記7つになります。
よく使われるものだったり、あまり使われない・知らない拡張機能もあるので、その補足も添えながら発表させていただきます。
ERC721拡張機能として実装が存在するのに、意外と知らないものもあるためこの機会にまとめてみようと思い記事にして発表しました。

:::note info
**ERC721**については以下の記事を参考にしてください。
:::

https://chaldene.net/erc721

# ERC721Pausable

まずは「**ERC721Pausable**」から紹介していきます。
この拡張機能はよく使われる機能です。

![17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/84c142ec-da4d-0d95-b049-d45008a90e47.png)

どんな機能か一言で言うと「**NFTの送付機能（`Transfer`）をオン・オフする**」ものです。

![18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/1bf285ad-90e2-cf97-8be1-03e04e4955f8.png)

もう少し詳しく説明すると、ある値をオンにしたりオフにしたりすることで送付機能の制御を実行できるようになっています。
使用される場面としては、何かしらの不正やハッキングなどの攻撃を受けた際に、NFTを不正に盗られないように送付機能（`Transfer`）を止めるなどが挙げられます。
また、送付機能（`Transfer`）に限らず、他の処理にも同じようにある値をオン・オフにすることで機能を止めたり、再起動することもできます。

# ERC721Burnable

次に「**ERC721Burnable**」を紹介していきます。
この拡張機能もよく使われる機能です。

![20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/dce3564e-ee8c-5cb5-27a2-95f0ec2cd17f.png)

機能を一言で説明すると、「**NFTをバーンする**」となります。


![21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/ea387ef3-1403-51a0-a175-2353404a0cbf.png)

もう少し詳しく説明します。

「**バーン**」もしくは「**燃やす**」というのは、NFTを0アドレスに送ることを指します。
0アドレスとは所有者がいないアドレスで、一度0アドレスに送ってしまったトークンは誰も取り出せないようになっています。
そのため、実質破棄しているような動作になっています。
この拡張機能が使用される場面としては、「**あるNFTをバーンして、新たなNFTを取得する**」などが挙げられます。

# ERC721Consective

次に「**ERC721Consective**」を紹介していきます。
この拡張機能はあまり知られていない拡張機能になります。

![23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/57648d45-5f2a-8077-e5cc-8aefc57ea295.png)

機能を一言で説明すると、「**複数のNFTを一気に作成する**」となります。

![24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/244fd311-c86f-7422-72a6-c266294089b4.png)

仕組みとしては、連続したトークンIDと呼ばれるNFTに振られている、ユニークな番号を持つNFTを一気に複数発行できるようになっています。
この機能を使用することで、NFTを発行するガス代を節約できます。
ただ、この機能は特殊で、**コントラクトの作成時のみ**実行することができます。
また、発行できる最大量を設定できます。

:::note warn
最大量を設定することで、NFT自体の最大発行量を超えることやトランザクションが失敗することを防ぐことができます。
デフォルトは`5000`となっています。
:::

![25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/7041966d-59b0-b362-a1ea-a17498b11d68.png)

ここで1つ疑問が浮かびます。

「**なぜコントラクト作成時のみ実行可能なのか？**」

この回答しては、「**連続したトークンID**」という部分を確保するためです。
連続したトークンIDのNFTを発行し終わる前に他の処理が走ってしまうと、「**連続したトークンID**」を守れない可能性が出てきます。
また、予測していない処理が走ることがないように、同時に発行処理が実行されないコントラクトのデプロイ時に実行されるようになっています。

# ERC721URIStorage

次に「**ERC721URIStorage**」を紹介していきます。
この拡張機能はよく使われる機能です。

![27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/9357a09e-2800-f62b-0ed5-0ee331aa57ed.png)


機能を一言で説明すると、「**コントラクト内でURI情報を管理する**」となります。

:::note info
URIとは。データや情報、またはそれらがどこにあるのかのURLなどの情報のことです。
:::

![28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/ecdcf38c-c83d-5014-8c1b-c989e08dc379.png)

コントラクト内でNFTのURIやメタデータ（データの説明や構造のこと）を管理しています。

https://wa3.i-3-i.info/word15688.html

**コントラクト内**というのがポイントになります。

独自にカスタマイズしたURIを設定してNFTに紐づけることができます。

![29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/bdc39232-8da3-bff3-2eb0-0f5f527dd37b.png)

そもそも**ERC721**自体にもURIの機能は存在します。
では、どの部分が異なるのでしょうか？
答えとしては、先ほどポイントとなるといった「**コントラクト内**」でURI情報を管理していることと、「**独自にカスタマイズできる**」ことになります。
ERC721では、基本的にURLなどの情報を格納できるのですが、独自にカスタマイズしたり、コントラクト内にメタデータの情報を持たせることはできません。
そのため、**ERC721URIStorage**を使用することで、表現の幅が広がります。

# ERC721Votes

次に「**ERC721Votes**」を紹介していきます。
この拡張機能はあまり知られていない機能です。

![31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/3e7168b4-71d9-9646-a7c2-ecc2d66dcf07.png)

機能を一言で説明すると、「**NFTを利用した投票権の委任と追跡を行う**」となります。

![32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/c38c03c9-a9f3-8e34-97af-54c24242a2b1.png)

なかなかわかりづらい機能なのでもう少し詳しく説明します。

ユーザーは所有しているNFTの数だけ投票権を持てます。
各ユーザーは自分自身、もしくは他のアドレスに対して投票権を委任することができます。
この委任をすることで投票権をアクティブにすることができます。

![33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/6b140d50-62f6-278d-45d1-683a29267738.png)

投票権をアクティブにすることで、投票に使用することができます。
一方、アクティブにしていない投票権は特定の投票で使用できなくなります。
また、この拡張機能は投票権の委任とその管理を行うだけなので、投票機能自体は別コントラクトを作成する必要があります。

# ERC721Royalty

次に「**ERC721Royalty**」を紹介していきます。
この拡張機能は知っている人は多いと思います。

![35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/082a62f2-c44f-f65f-07dc-21405fbd1deb.png)

機能を一言で説明すると、「**ロイヤリティを強制化できる**」となります。

:::note info
ロイヤリティとは、NFTが二次流通した時に、売り上げの一部がクリエイターに入る仕組みのことです。
:::

![36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/f7b32059-0c41-3081-ac20-0bd189090098.png)

NFTの売却価格と事前に設定されたパーセンテージ（10%など）を使用して、ロイヤリティを計算します。
NFTを購入するときは、ロイヤリティを支払わないと購入処理が実行されないようになっています。

![37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/f5ba9758-72b4-67c9-aaf5-122ae62bcd77.png)

ここで疑問が浮かびます。

「**ほんとにロイヤリティを強制できるの？**」

答えとしてはできません。
理由としては、結局はマーケットプレイスの実装次第になってしまうためです。
マーケットプレイス内で資金の受け渡しを行い、送付機能（`Transfer`）を使用するとこの機能は意味をなさなくなります。
現在もこの二次流通のロイヤリティについては、多くの人がなんとか実装できないか悩んでいるのが現状です。

# ERC721Wrapper

次に「**ERC721Wrapper**」を紹介していきます。
この拡張機能はあまり知られていません。

![39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/de4240ee-0237-2ae6-aa29-0220ba82bef6.png)

機能を一言で説明すると、「**NFTをもとに別のトークンを発行する**」となります。

![40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/5e4d4caf-bbc6-268d-ba5e-180dd5af3bec.png)

NFTをこの拡張機能を実装しているコントラクトに預けることで、同じトークンIDを持つ別のトークンを発行することができます。
これを「**ラップする**」と言います。
また、ラップされたトークンをバーンすることで、元のNFTを取り戻すことができます。

![41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/17172816-02f4-7320-f07d-98b7f0ededd9.png)

この「**ラップ**」については、「ところてん」をイメージするとわかりやすいかと思います。
一方からあるNFTを入れると、もう片方から別のトークンが出てくる仕組みになっています。

![42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/0747bcc6-2b52-0a10-c90b-2c52c718b506.png)

使用場面としては以下が挙げられます。

- Aというゲーム（カードゲーム）内で使用されているNFTをラップして、Bというゲーム（RPG）で使用できるNFTを取得する。
- 所有しているNFTレンタルするために、対象のNFTをラップした所有権を表すトークンを取得する。
- 1つのNFTをラップして、複数の装備アイテムトークンを取得する。

# 最後に

今回は「OpenZeppelinで実装されている**ERC721**の拡張機能」について、まとめた記事と、勉強会での発表資料をもとに簡単に記事にしました。

いかがだったでしょうか？

より詳しく知りたい方は以下の記事を参考にしてください。

https://chaldene.net/erc721-extension

質問などがある方は以下のTwitterのDMなどからお気軽に質問してください！

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

# 採用強化中！

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

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

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