[ERC1046] ERC20のメタデータをERC721のようにする仕組みを理解しよう！

# はじめに

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

https://cryptogames.co.jp/

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

https://cryptospells.jp/

今回は、**ERC20**のメタデータを**ERC721**のメタデータのように変更する拡張機能である**ERC1046**についてまとめていきます！

:::note info
以下にまとめられているものをChatGPTも使用しながら、翻訳・要約・補足してまとめていきます。
:::

https://eips.ethereum.org/EIPS/eip-1046

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

https://chaldene.net/erc721

# 概要
**ERC721**は、イーサリアムブロックチェーン上で非代替可能トークン（NFT）を作成するための標準規格です。
これにより、異なるデジタルアセットやコレクティブルなアイテムを一意に識別し、所有権をトークンとして表現できます。
**ERC721**は、それぞれのトークンに関連するメタデータを扱うための`tokenURI`関数を導入しました。

`tokenURI`は、各**ERC721**トークンのメタデータを格納しているJSON形式のURIを返す関数です。
メタデータには、サムネイル画像、タイトル、説明、アセットのプロパティなどが含まれます。
これにより、NFTの詳細情報を外部に格納し、スマートコントラクトを軽量に保ちながら、トークンを見る際に必要な情報を提供することができます。

:::note info

メタデータは以下のようなJSON形式で表現されます。
```json
{
    "title": "Asset Metadata",
    "type": "object",
    "properties": {
        "name": {
            "type": "string",
            "description": "Identifies the asset to which this NFT represents"
        },
        "description": {
            "type": "string",
            "description": "Describes the asset to which this NFT represents"
        },
        "image": {
            "type": "string",
            "description": "A URI pointing to a resource with mime type image/* representing the asset to which this NFT represents. Consider making any images at a width between 320 and 1080 pixels and aspect ratio between 1.91:1 and 4:5 inclusive."
        }
    }
}
```
引用: https://eips.ethereum.org/EIPS/eip-721
:::

**ERC20**は、イーサリアム上で最も一般的なトークン標準規格であり、通常のトークン（代替可能トークン）を作成します。
これまでの**ERC20**では、トークンのメタデータを直接スマートコントラクト内に含めることが一般的でした。
しかし、**ERC721**のメタデータ処理の利点を活用するために、このERCでは**ERC20**にも`tokenURI`関数を導入しています。
これにより、**ERC20**トークンもURIを通じてメタデータを外部に保存できるようになります。

![metadata.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/8f6da649-a022-51cc-7295-856142b5cb24.png)

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

https://chaldene.net/erc20

:::note info
**ERC20**のメタデータは、「`name`」、「`symbol`」、「`decimals`」などの値です。
:::

**ERC1155**は、複数のトークンタイプを1つのスマートコントラクトで管理するための標準規格です。
つまり、非代替可能トークン（**ERC721**）と代替可能トークン（**ERC20**）の両方の特性を持つことができます。
このERCでは、**ERC1155**も`tokenURI`関数を拡張し、**ERC721**と**ERC20**との相互運用性を強化しています。

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

https://chaldene.net/erc1155

これらのトークン標準が同じ`tokenURI`関数を持つことで、以下の利点があります。

1. コントラクトがどのタイプのトークン（**ERC20**、**ERC721**、**ERC1155**）かを判別できます。
これにより、スマートコントラクトとトークンのタイプを効率的に特定することができます。

2. ユーザーに対してトークンの詳細情報を提供する方法が統一されます。
例えば、アセットリストページや専用のトークンページで、トークンのメタデータを表示する際に同じメカニズムを使用できます。

3. トークンの機能を特定する際に、メタデータを使用してより多くの情報を取得できます。
トークンの用途や特性を理解しやすくなります。

![metadata2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/8da51f81-a485-05f4-e13c-b730baa36a4c.png)


これらの相互運用性とメタデータの統一化は、トークンエコシステムの柔軟性と拡張性を向上させ、ユーザーにとってもより使いやすい環境を提供します。

# 仕様

## 相互運用メタデータ

```javascript
interface InteroperabilityMetadata {
    erc1046?: boolean | undefined;

    erc721?: boolean | undefined;

    erc1155?: boolean | undefined;
}
```

これらのフィールドはすべてオプションであり、必要に応じてどれか1つもしくは複数のフィールドを含めることができます。
これにより、あるトークンがどのタイプのトークンであるかを効率的に判別し、ウォレットや他のプラットフォームにとって使いやすくすることができます。
また、「**すべてのフィールドが`bool`値である必要はない**」と明示されています。

### erc1046
このフィールドが`true`の場合、**ERC1046**のトークンメタデータであることを示します。
`false`場合、このフィールドは省略されます。
このフィールドが`true`に設定されていると、ウォレットに対してこのアドレスを**ERC20**トークンとして扱うよう指示されます。

### erc721
このフィールドが`true`の場合、**ERC721**のトークンメタデータであることを示します。
`false`場合、このフィールドは省略されます。
このフィールドが`true`に設定されていると、ウォレットに対してこのアドレスを**ERC721**トークンとして扱うよう指示されます。

### erc1155
このフィールドが`true`の場合、**ERC1155**のトークンメタデータであることを示します。
`false`場合、このフィールドは省略されます。
このフィールドが`true`に設定されていると、ウォレットに対してこのアドレスを**ERC1155**トークンとして扱うよう指示されます。

## ERC20拡張機能

### ERC20インタフェース拡張

```javascript
pragma solidity ^0.8.0;

interface ERC20TokenMetadata /* is ERC20 */ {
    function tokenURI() external view returns (string);
}
```

### tokenURI

**ERC721**トークンのようなトークンURIを取得する関数。
トークンURIとは、トークンの詳細情報やメタデータを格納するためのURI（Uniform Resource Identifier）のことです。
この関数を呼び出すことで、トークンに関連するメタデータを取得することができます。

メタデータはJSON形式で提供される必要があります。
さらに、このJSONデータは**ERC1046**の**ERC-20 Token Metadata Schema**をサポートしている必要があります。
**ERC1046**は、**ERC20**トークンにメタデータを拡張するための標準規格です。

このインターフェースは、**ERC20**トークンに対して**ERC721**のようなトークンURIを提供し、メタデータの取得を簡素化することを可能にします。
これにより、ウォレットやDAppなどのプラットフォームは、トークンの詳細情報を簡単に表示できるようになります。
また、**ERC1046**のスキーマをサポートすることで、トークンのメタデータの一貫性と相互運用性を確保することができます。

## ERC-20 Token Metadata Schema


```javascript
interface ERC20TokenMetadata {
    interop: InteroperabilityMetadata;
    
    name?: string;
    
    symbol?: string;

    decimals?: number;
    
    description?: string;
    
    image?: string;
    
    images?: string[];
    
    icons?: string[];
}
```

### interop
トークンの相互運用性に関する情報を表現するためのフィールド。
詳細は別のインターフェースで定義される「**InteroperabilityMetadata**」に記載されています。
これにより、トークンの種類を区別し、それに対応するURIを取得できます。

### name
**ERC20**トークンの名称を表す文字列。
トークンの名前を取得するための関数が**ERC20**トークン内に存在する場合、このフィールドの値はその関数の返り値と一致する必要があります。

### symbol
**ERC20**トークンのシンボルを表す文字列。
トークンのシンボルを取得するための関数が**ERC20**トークン内に存在する場合、このフィールドの値はその関数の返り値と一致する必要があります。

### decimals
**ERC20**トークンの小数点以下の桁数を表す整数値。
トークンの小数点以下の桁数を取得するための関数が**ERC20**トークン内に存在する場合、このフィールドの値はその関数の返り値と一致する必要があります。
ただし、そのような関数が存在しない場合はデフォルト値として`18`が設定されます。

### description
**ERC20**トークンに関する簡潔な説明を表す文字列。
このフィールドは、任意のマークアップや改行を含まない1段落の説明を提供します。

### image
**ERC20**トークンを表現するための画像のURIを表す文字列。
画像は`image/*`というMIMEタイプを持つリソースを指すURIであり、トークンを視覚的に表現します。
画像がビットマップ形式の場合、幅は`320`から`1080`ピクセルの範囲内にあるべきです。
また、アスペクト比は`1.91:1`から`4:5`までの範囲内です。

### images
**ERC20**トークンを表現するための複数の画像のURIを表す文字列の配列。
上記の`image`フィールドと同様の要件が適用されます。

### icons
**ERC20**トークンのアイコンを表現するための複数の画像のURIを表す文字列の配列。
アイコンは、アスペクト比が`1:1`であり、透明な背景を使用するビットマップ形式の画像です。
幅は`320`から`1080`ピクセルの範囲内にあり、高さは幅と等しいです。

これらのメタデータフィールドによって、**ERC20**トークンに関するさまざまな情報を一貫して表現できるようになります。
これにより、ウォレットやDAppなどのプラットフォームは、トークンを視覚的に表現するための画像を取得したり、トークンの名前やシンボルを表示したりできます。

## ERC721拡張機能

###  Extension to the ERC-721 Metadata Schema

```javascript
interface ERC721TokenMetadataInterop extends ERC721TokenMetadata {
    interop: InteroperabilityMetadata;
}
```

## ERC1155拡張機能


###  ERC-1155 Interface Extension

```javascript
pragma solidity ^0.8.0;

interface ERC1155TokenMetadataInterop /* is ERC1155Metadata */ {
    function tokenURI() external view returns (string);
}
```

### ERC-1155 Metadata Schema

**ERC1155**を実装し、そのトークンメタデータURIを使用するコントラクトは、メタデータURIに以下の拡張を使用することが推奨されます。

```javascript
interface ERC1155TokenMetadataInterop extends ERC1155TokenMetadata {
    interop: InteroperabilityMetadata;
}
```

「**相互運用性メタデータ**」（InteroperabilityMetadata）と呼ばれるインターフェースを参照します。
相互運用性メタデータには、トークンの相互運用性に関する情報が含まれています。
具体的には、**ERC20**トークンメタデータ拡張で説明したようなフィールド（`erc1046`、`erc721`、`erc1155`）が含まれています。
これにより、`ERC1155TokenMetadataInterop`を利用するコントラクトは、トークンのURIを解釈する際に、適切な規格（**ERC20**、**ERC721**、**ERC1155**）を認識できるようになります。
**ERC1155**トークンのメタデータスキーマに対するこの拡張によって、トークン間のURIの区別を明確にし、相互運用性を向上させることができます。
これにより、異なる規格を持つ**ERC1155**トークンをより効率的に取り扱うことができるようになります。

## その他の推奨事項

ガス代を節約するため、コントラクトは`name()`、`symbol()`、`decimals()`のオプションの関数を実装しないことが推奨されます。
代わりに、これらの情報はメタデータURIにのみ含めるようにすることが推奨されます。
また、`decimals`が`18`である場合は、デフォルトデータであるためメタデータに`decimals`フィールドを含めないことが推奨されます。

# 補足

このERCは、開発者に対して**ERC20**トークンへのメタデータの追加を簡単にし、全体のエコシステムには最小限の影響のみに抑えることを目的としています。
パラメータの名前を共通化することで、コードの再利用が容易になります。

トークン間の相互運用性を実現することは重要であり、トークンのタイプを区別することが簡単ではない場合があります。
相互運用性を実現するためには**ERC165**を使用することもできますが、静的な呼び出しはウォレットやウェブサイトにとって時間がかかり、柔軟性が制限される場合があります。
そのため、トークンURIに相互運用性データを含めることで、柔軟性が向上し、パフォーマンスが向上します。

# 後方互換性
このEIPは完全な互換性を持っており、**ERC20**トークンの機能を拡張するだけであり、オプション機能であるため、完全に後方互換性があります。
また、**ERC721**および**ERC1155**トークンに対しても後方互換性を保つための推奨事項があります。

# セキュリティ
サーバーサイドリクエストフォージェリ（SSRF）への注意が必要です。
ウォレットはURIに対して任意のリクエストを送信する際に注意を払う必要があります。
ウォレットは、特定のスキームやポートをホワイトリストに登録することでURIを検証することが推奨されます。
脆弱なウォレットは、例えばローカルにホストされたredisデータベースのデータを改ざんされる可能性があります。

# 引用

Tommy Nicholas (@tomasienrbc), Matt Russo (@mateosu), John Zettler (@JohnZettler), Matt Condon (@shrugs), Gavin John (@Pandapip1), "ERC-1046: tokenURI Interoperability," Ethereum Improvement Proposals, no. 1046, April 2018. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-1046.

# 考察
**ERC1046**は、**ERC20**のメタデータを**ERC721**のようにする拡張機能です。
**ERC20**では、メタデータをコントラクト内で管理しているため、コントラクト外で管理できるようにもできるとのことで面白いと思いました。
ただ、実際に活用できる場面が浮かんできません。
どのような場面でこの規格が役立つかもわかっていないため、あまり使われない規格なのではないかと思います。
ぜひ活用場面をが思い浮かぶ人はコメントしてください！

# 最後に

今回は「**ERC20**のメタデータを**ERC721**のメタデータのように変更する拡張機能である**ERC1046**」についてまとめてきました！
いかがだったでしょうか？

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

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

# 採用強化中！

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

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

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