[ERC7409] より多くの絵文字をコントラクトで管理する仕組みを理解しよう！

# はじめに

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

https://cryptogames.co.jp/

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

https://cryptospells.jp/

今回は、**ERC6381**を拡張して、一括処理機能の追加と扱える絵文字を増やす提案している規格である**ERC7409**についてまとめていきます！

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

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

他にも様々なERCについてまとめています。

https://cardene.notion.site/ERC-EIP-2a03fa3ea33d43baa9ed82288f98d4a9?pvs=4

# 概要

**ERC7409**は、**ERC6381**の後継として提案された新しい規格です。
この提案の核となるのは、「**公開非代替トークン（NFT）エモートリポジトリ標準（Public Non-Fungible Tokens Emote Repository standard）**」というもので、**ERC721**や**ERC1155**といったNFTに対して新たなインタラクティブな機能を加えることを目的としています。

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

https://qiita.com/cardene/items/d22d76d1cf66c34f1e57

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

https://chaldene.net/erc721

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

https://chaldene.net/erc1155

NFTに対して絵文字を使った反応を可能にする機能です。
これらの絵文字はユニコードで標準化されており、ユーザーはこれらの絵文字を使ってNFTに対する感情や反応を示すことができます。
この機能は「**公開非ゲートリポジトリ（public non-gated repository）**」と呼ばれるスマートコントラクトを通じて実装され、異なるネットワーク上でも同じアドレスでアクセスできるようになっています。

:::note info
**ERC7409**は、ユーザーがNFTに絵文字でリアクションを示すことを可能にする新しい方法です。
これにより、NFTのやり取りがよりエンゲージメント豊かで、インタラクティブな体験になることが期待されます。
全てのネットワークで利用可能なこの公開リポジトリを通じて、NFTに対する新しい形のやり取りが実現されます。
:::

# 動機

Ethereumのエコシステムでは、NFT（非代替トークン）が広く使用されており、様々な用途で利用されています。
様々なERCなどの提案で、NFTに新たな機能を加え標準化しています。
具体的には、誰もがNFTとやり取りできるようにすることで、NFTの所有にインタラクティブな要素を加え、フィードバックに基づく新しいNFTのメカニズムを開発しています。

この新しい提案（**ERC-721**ベースのトークンに新しいユーティリティを提供する）は、以下の3つの分野で新しい機能を提供します。

1. インタラクティビティ（Interactivity）
2. フィードバックに基づく進化（Feedback based evolution）
3. 評価（Valuation）

この提案はまた、**ERC6381**のインターフェースの互換性問題を解決します。
元々、絵文字は`bytes4`の値で表現されていましたが、絵文字のバリエーションフラグや肌の色トーンが加わったことで、`bytes4`ではすべての絵文字を表現するのに不十分になりました。
そのため、新しい標準では文字列（`string`）を使用するように変更されています。
この変更を除けば、この提案は**ERC6381**と機能的には同じです。

:::note info
この提案はNFTのやり取りをもっとインタラクティブにし、フィードバックに基づく進化や評価の機能を追加することを目指しています。
また、絵文字をより柔軟に表現できるようにデータ形式を改善しています。
:::

了解しました。このテキストは、NFTに追加される新しい機能がもたらす3つの主な利点について説明しています。それをもう少し簡単に説明します。

## Interactivity
NFTに絵文字で反応（エモート）できるようにすることで、NFTをよりインタラクティブにします。
これは、NFTに感心を示す人が絵文字で反応を示すこと、またはトークンの所有者の行動に対する反応を意味します。
多くの人からエモートを集めたトークンは、ユニークさや価値が高まるかもしれません。

### Feedback based evolution
NFTへの標準化されたオンチェーンの反応により、フィードバックに基づいてトークンが進化することが可能になります。
現在の多くの方法は信頼性に欠けたり、操作可能なオフチェーンのものです。
オンチェーンでやり取りを追跡することで、トークンの信頼性が高まり、客観的に評価されるようになります。
また、特定の反応の量に達するとトークンが進化するように設計されることで、コレクションへの関心が高まります。

### Valuation
現在のNFT市場は、トークンの過去の取引価格や市場データに依存していますが、リアルタイムでの人気や欲求度を示す指標はありません。
トークンに対してユーザーが絵文字で反応する能力を加えることで、トークンに対する印象に基づいて価値を評価する新しい方法が提供されます。
これにより、買い手や売り手はトークンの真の価値をよりよく判断できるようになります。

# 仕様

```javascript
/// @title ERC-7409 Emotable Extension for Non-Fungible Tokens
/// @dev See https://eips.ethereum.org/EIPS/eip-7409
/// @dev Note: the ERC-165 identifier for this interface is 0x1b3327ab.

pragma solidity ^0.8.16;

interface IERC7409 /*is IERC165*/ {
    /**
     * @notice Used to notify listeners that the token with the specified ID has been emoted to or that the reaction has been revoked.
     * @dev The event MUST only be emitted if the state of the emote is changed.
     * @param emoter Address of the account that emoted or revoked the reaction to the token
     * @param collection Address of the collection smart contract containing the token being emoted to or having the reaction revoked
     * @param tokenId ID of the token
     * @param emoji Unicode identifier of the emoji
     * @param on Boolean value signifying whether the token was emoted to (`true`) or if the reaction has been revoked (`false`)
     */
    event Emoted(
        address indexed emoter,
        address indexed collection,
        uint256 indexed tokenId,
        string emoji,
        bool on
    );

    /**
     * @notice Used to get the number of emotes for a specific emoji on a token.
     * @param collection Address of the collection containing the token being checked for emoji count
     * @param tokenId ID of the token to check for emoji count
     * @param emoji Unicode identifier of the emoji
     * @return Number of emotes with the emoji on the token
     */
    function emoteCountOf(
        address collection,
        uint256 tokenId,
        string memory emoji
    ) external view returns (uint256);

    /**
     * @notice Used to get the number of emotes for a specific emoji on a set of tokens.
     * @param collections An array of addresses of the collections containing the tokens being checked for emoji count
     * @param tokenIds An array of IDs of the tokens to check for emoji count
     * @param emojis An array of unicode identifiers of the emojis
     * @return An array of numbers of emotes with the emoji on the tokens
     */
    function bulkEmoteCountOf(
        address[] memory collections,
        uint256[] memory tokenIds,
        string[] memory emojis
    ) external view returns (uint256[] memory);

    /**
     * @notice Used to get the information on whether the specified address has used a specific emoji on a specific
     *  token.
     * @param emoter Address of the account we are checking for a reaction to a token
     * @param collection Address of the collection smart contract containing the token being checked for emoji reaction
     * @param tokenId ID of the token being checked for emoji reaction
     * @param emoji The ASCII emoji code being checked for reaction
     * @return A boolean value indicating whether the `emoter` has used the `emoji` on the token (`true`) or not
     *  (`false`)
     */
    function hasEmoterUsedEmote(
        address emoter,
        address collection,
        uint256 tokenId,
        string memory emoji
    ) external view returns (bool);

    /**
     * @notice Used to get the information on whether the specified addresses have used specific emojis on specific
     *  tokens.
     * @param emoters An array of addresses of the accounts we are checking for reactions to tokens
     * @param collections An array of addresses of the collection smart contracts containing the tokens being checked
     *  for emoji reactions
     * @param tokenIds An array of IDs of the tokens being checked for emoji reactions
     * @param emojis An array of the ASCII emoji codes being checked for reactions
     * @return An array of boolean values indicating whether the `emoter`s has used the `emoji`s on the tokens (`true`)
     *  or not (`false`)
     */
    function haveEmotersUsedEmotes(
        address[] memory emoters,
        address[] memory collections,
        uint256[] memory tokenIds,
        string[] memory emojis
    ) external view returns (bool[] memory);

    /**
     * @notice Used to get the message to be signed by the `emoter` in order for the reaction to be submitted by someone
     *  else.
     * @param collection The address of the collection smart contract containing the token being emoted at
     * @param tokenId ID of the token being emoted
     * @param emoji Unicode identifier of the emoji
     * @param state Boolean value signifying whether to emote (`true`) or undo (`false`) emote
     * @param deadline UNIX timestamp of the deadline for the signature to be submitted
     * @return The message to be signed by the `emoter` in order for the reaction to be submitted by someone else
     */
    function prepareMessageToPresignEmote(
        address collection,
        uint256 tokenId,
        string memory emoji,
        bool state,
        uint256 deadline
    ) external view returns (bytes32);

    /**
     * @notice Used to get multiple messages to be signed by the `emoter` in order for the reaction to be submitted by someone
     *  else.
     * @param collections An array of addresses of the collection smart contracts containing the tokens being emoted at
     * @param tokenIds An array of IDs of the tokens being emoted
     * @param emojis An array of unicode identifiers of the emojis
     * @param states An array of boolean values signifying whether to emote (`true`) or undo (`false`) emote
     * @param deadlines An array of UNIX timestamps of the deadlines for the signatures to be submitted
     * @return The array of messages to be signed by the `emoter` in order for the reaction to be submitted by someone else
     */
    function bulkPrepareMessagesToPresignEmote(
        address[] memory collections,
        uint256[] memory tokenIds,
        string[] memory emojis,
        bool[] memory states,
        uint256[] memory deadlines
    ) external view returns (bytes32[] memory);

    /**
     * @notice Used to emote or undo an emote on a token.
     * @dev Does nothing if attempting to set a pre-existent state.
     * @dev MUST emit the `Emoted` event is the state of the emote is changed.
     * @param collection Address of the collection containing the token being emoted at
     * @param tokenId ID of the token being emoted
     * @param emoji Unicode identifier of the emoji
     * @param state Boolean value signifying whether to emote (`true`) or undo (`false`) emote
     */
    function emote(
        address collection,
        uint256 tokenId,
        string memory emoji,
        bool state
    ) external;

    /**
     * @notice Used to emote or undo an emote on multiple tokens.
     * @dev Does nothing if attempting to set a pre-existent state.
     * @dev MUST emit the `Emoted` event is the state of the emote is changed.
     * @dev MUST revert if the lengths of the `collections`, `tokenIds`, `emojis` and `states` arrays are not equal.
     * @param collections An array of addresses of the collections containing the tokens being emoted at
     * @param tokenIds An array of IDs of the tokens being emoted
     * @param emojis An array of unicode identifiers of the emojis
     * @param states An array of boolean values signifying whether to emote (`true`) or undo (`false`) emote
     */
    function bulkEmote(
        address[] memory collections,
        uint256[] memory tokenIds,
        string[] memory emojis,
        bool[] memory states
    ) external;

    /**
     * @notice Used to emote or undo an emote on someone else's behalf.
     * @dev Does nothing if attempting to set a pre-existent state.
     * @dev MUST emit the `Emoted` event is the state of the emote is changed.
     * @dev MUST revert if the lengths of the `collections`, `tokenIds`, `emojis` and `states` arrays are not equal.
     * @dev MUST revert if the `deadline` has passed.
     * @dev MUST revert if the recovered address is the zero address.
     * @param emoter The address that presigned the emote
     * @param collection The address of the collection smart contract containing the token being emoted at
     * @param tokenId IDs of the token being emoted
     * @param emoji Unicode identifier of the emoji
     * @param state Boolean value signifying whether to emote (`true`) or undo (`false`) emote
     * @param deadline UNIX timestamp of the deadline for the signature to be submitted
     * @param v `v` value of an ECDSA signature of the message obtained via `prepareMessageToPresignEmote`
     * @param r `r` value of an ECDSA signature of the message obtained via `prepareMessageToPresignEmote`
     * @param s `s` value of an ECDSA signature of the message obtained via `prepareMessageToPresignEmote`
     */
    function presignedEmote(
        address emoter,
        address collection,
        uint256 tokenId,
        string memory emoji,
        bool state,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @notice Used to bulk emote or undo an emote on someone else's behalf.
     * @dev Does nothing if attempting to set a pre-existent state.
     * @dev MUST emit the `Emoted` event is the state of the emote is changed.
     * @dev MUST revert if the lengths of the `collections`, `tokenIds`, `emojis` and `states` arrays are not equal.
     * @dev MUST revert if the `deadline` has passed.
     * @dev MUST revert if the recovered address is the zero address.
     * @param emoters An array of addresses of the accounts that presigned the emotes
     * @param collections An array of addresses of the collections containing the tokens being emoted at
     * @param tokenIds An array of IDs of the tokens being emoted
     * @param emojis An array of unicode identifiers of the emojis
     * @param states An array of boolean values signifying whether to emote (`true`) or undo (`false`) emote
     * @param deadlines UNIX timestamp of the deadline for the signature to be submitted
     * @param v An array of `v` values of an ECDSA signatures of the messages obtained via `prepareMessageToPresignEmote`
     * @param r An array of `r` values of an ECDSA signatures of the messages obtained via `prepareMessageToPresignEmote`
     * @param s An array of `s` values of an ECDSA signatures of the messages obtained via `prepareMessageToPresignEmote`
     */
    function bulkPresignedEmote(
        address[] memory emoters,
        address[] memory collections,
        uint256[] memory tokenIds,
        string[] memory emojis,
        bool[] memory states,
        uint256[] memory deadlines,
        uint8[] memory v,
        bytes32[] memory r,
        bytes32[] memory s
    ) external;
}
```

## Event

### Emoted

```javascript
event Emoted(
    address indexed emoter,
    address indexed collection,
    uint256 indexed tokenId,
    string emoji,
    bool on
);
```

**概要**

特定のIDを持つトークンに対して絵文字反応が行われたか、または反応が取り消されたことをリスナーに通知するイベント。

**詳細**

このイベントは、トークンに対する絵文字の反応の状態が変更された場合のみ発行されるべきです。
これにより、トークンに対する絵文字反応の追加や取り消しのアクションがブロックチェーン上で追跡可能になります。

**パラメータ**

- `emoter`
    - トークンに絵文字反応を行ったり取り消したりしたアカウントのアドレス。
- `collection`
    - 反応されたトークンを含むコレクションのスマートコントラクトのアドレス。
- `tokenId`
    - 反応されたトークンのID。
- `emoji`
    - 絵文字のユニコード識別子。
- `on`
    - トークンに対して絵文字反応が行われたことを示す真偽値（`true`）、または反応が取り消されたことを示す（`false`）。

---

## 関数

### `emoteCountOf`

```javascript
function emoteCountOf(
    address collection,
    uint256 tokenId,
    string memory emoji
) external view returns (uint256);
```

**概要**

特定の絵文字に対するトークンのエモート（反応）の数を取得する関数。

**詳細**

この関数は、指定されたトークンに対して特定の絵文字でどれだけのエモートが行われたかの数を返します。

**引数**

- `collection`
    - トークンを含むコレクションのスマートコントラクトのアドレス。
- `tokenId`
    - エモートの数を確認するトークンのID。
- `emoji`
    - 絵文字のユニコード識別子。

**戻り値**

- トークンに対する指定された絵文字のエモートの数。

---

### `bulkEmoteCountOf`

```javascript
function bulkEmoteCountOf(
    address[] memory collections,
    uint256[] memory tokenIds,
    string[] memory emojis
) external view returns (uint256[] memory);
```

**概要**

複数のトークンに対する特定の絵文字のエモート数を一括で取得する関数。

**詳細**

この関数は、複数のトークンに対して特定の絵文字で行われたエモートの数を配列として返します。

**引数**

- `collections`
    - トークンを含むコレクションのスマートコントラクトのアドレスの配列。
- `tokenIds`
    - エモートの数を確認するトークンのIDの配列。
- `emojis`
    - 絵文字のユニコード識別子の配列。

**戻り値**

- トークンに対する指定された絵文字のエモートの数の配列。

---

### `hasEmoterUsedEmote`

```javascript
function hasEmoterUsedEmote(
    address emoter,
    address collection,
    uint256 tokenId,
    string memory emoji
) external view returns (bool);
```

**概要**

特定のアドレスが特定のトークンに対して特定の絵文字を使用したかどうかの情報を取得する関数。

**詳細**

この関数は、指定されたアドレスが指定されたトークンに対して特定の絵文字でエモートを行ったかどうかを真偽値で返します。

**引数**

- `emoter`
    - エモートを行ったか確認するアカウントのアドレス。
- `collection`
    - トークンを含むコレクションのスマートコントラクトのアドレス。
- `tokenId`
    - エモートを確認するトークンのID。
- `emoji`
    - 絵文字のユニコード識別子。

**戻り値**

- 指定されたアドレスが指定されたトークンに対して特定の絵文字を使用しているかどうかを示す真偽値。

---

### `haveEmotersUsedEmotes`

```javascript
function haveEmotersUsedEmotes(
    address[] memory emoters,
    address[] memory collections,
    uint256[] memory tokenIds,
    string[] memory emojis
) external view returns (bool[] memory);
```

**概要**

複数のアドレスが特定のトークンに対して特定の絵文字を使用したかどうかの情報を一括で取得する関数。

**詳細**

この関数は、複数のアドレスが複数のトークンに対して特定の絵文字でエモートを行ったかどうかを真偽値の配列で返します。

**引数**

- `emoters`
    - エモートを行ったか確認するアカウントのアドレスの配列。
- `collections`
    - トークンを含むコレクションのスマートコントラクトのアドレスの配列。
- `tokenIds`
    - エモートを確認するトークンのIDの配列。
- `emojis`
    - 絵文字のユニコード識別子の配列。

**戻り値**

- 指定されたアドレスが指定されたトークンに対して特定の絵文字を使用しているかどうかを示す真偽値の配列。

---

### `prepareMessageToPresignEmote`

```javascript
function prepareMessageToPresignEmote(
    address collection,
    uint256 tokenId,
    string memory emoji,
    bool state,
    uint256 deadline
) external view returns (bytes32);
```

**概要**

他の人がエモートを提出するためにエモーターが署名する必要があるメッセージを取得する関数。

**詳細**

この関数は、エモートを行うために必要なパラメータを含むメッセージを生成し、それを署名用のバイト列として返します。

**引数**

- `collection`
    - トークンを含むコレクションのスマートコントラクトのアドレス。
- `tokenId`
    - エモートされるトークンのID。
- `emoji`
    - 絵文字のユニコード識別子。
- `state`
    - エモートする（`true`）か取り消す（`false`）かを示す真偽値。
- `deadline`
    - 署名を提出するための期限となるUNIXタイムスタンプ。

**戻り値**

- 他人がエモートを提出するためにエモーターが署名する必要があるメッセージ。

---

### `bulkPrepareMessagesToPresignEmote`

```javascript
function bulkPrepareMessagesToPresignEmote(
    address[] memory collections,
    uint256[] memory tokenIds,
    string[] memory emojis,
    bool[] memory states,
    uint256[] memory deadlines
) external view returns (bytes32[] memory);
```

**概要**

複数のトークンに対して他者によって反応を提出するためにエモーターが署名する必要があるメッセージを取得する関数。

**詳細**

この関数は、複数のトークンに対する反応を他者が提出するために、エモーターが署名する必要があるメッセージを生成し、それらを配列として返します。

**引数**

- `collections`
    - トークンを含むコレクションのスマートコントラクトのアドレスの配列。
- `tokenIds`
    - エモートされるトークンのIDの配列。
- `emojis`
    - 絵文字のユニコード識別子の配列。
- `states`
    - エモートする（`true`）か取り消す（`false`）かを示す真偽値の配列。
- `deadlines`
    - 署名を提出するための期限となるUNIXタイムスタンプの配列。

**戻り値**

- 他人がエモートを提出するためにエモーターが署名する必要があるメッセージの配列。

---

### `emote`

```javascript
function emote(
    address collection,
    uint256 tokenId,
    string memory emoji,
    bool state
) external;
```

**概要**

トークンに対してエモートを行うか、エモートを取り消す関数。

**詳細**

この関数は、指定されたトークンに対してエモートを行うか取り消すかを行います。
エモートの状態が変わる場合にのみ`Emoted`イベントが発行されます。

**引数**

- `collection`
    - トークンを含むコレクションのスマートコントラクトのアドレス。
- `tokenId`
    - エモートされるトークンのID。
- `emoji`
    - 絵文字のユニコード識別子。
- `state`
    - エモートする（`true`）か取り消す（`false`）かを示す真偽値。

---

### `bulkEmote`

```javascript
function bulkEmote(
    address[] memory collections,
    uint256[] memory tokenIds,
    string[] memory emojis,
    bool[] memory states
) external;
```

**概要**

複数のトークンに対してエモートを行うか、エモートを一括で取り消す関数。

**詳細**

この関数は、複数のトークンに対してエモートを行うか取り消すかを一括で行います。
エモートの状態が変わる場合にのみ`Emoted`イベントが発行されます。
引数の配列の長さが一致していない場合、処理は失敗します。

**引数**

- `collections`
    - トークンを含むコレクションのスマートコントラクトのアドレスの配列。
- `tokenIds`
    - エモートされるトークンのIDの配列。
- `emojis`
    - 絵文字のユニコード識別子の配列。
- `states`
    - エモートする（`true`）か取り消す（`false`）かを示す真偽値の配列。

---

### `presignedEmote`

```javascript
function presignedEmote(
    address emoter,
    address collection

,
    uint256 tokenId,
    string memory emoji,
    bool state,
    uint256 deadline,
    uint8 v,
    bytes32 r,
    bytes32 s
) external;
```

**概要**

他人に代わってエモートを行うか取り消す関数。

**詳細**

この関数は、他人に代わってエモートを行うか取り消すために使用され、署名されたメッセージに基づいて処理を行います。
署名されたメッセージが有効でない場合、または期限が過ぎている場合、処理は失敗します。

**引数**

- `emoter`
    - エモートを事前に署名したアカウントのアドレス。
- `collection`
    - トークンを含むコレクションのスマートコントラクトのアドレス。
- `tokenId`
    - エモートされるトークンのID。
- `emoji`
    - 絵文字のユニコード識別子。
- `state`
    - エモートする（`true`）か取り消す（`false`）かを示す真偽値。
- `deadline`
    - 署名を提出するための期限となるUNIXタイムスタンプ。
- `v`, `r`, `s`
    - ECDSA署名の構成要素。

---

### `bulkPresignedEmote`

```javascript
function bulkPresignedEmote(
    address[] memory emoters,
    address[] memory collections,
    uint256[] memory tokenIds,
    string[] memory emojis,
    bool[] memory states,
    uint256[] memory deadlines,
    uint8[] memory v,
    bytes32[] memory r,
    bytes32[] memory s
) external;
```

**概要**

複数のトークンに対して他人に代わって一括でエモートを行うか取り消す関数。

**詳細**

この関数は、複数のトークンに対して他人に代わってエモートを行うか取り消すために使用され、署名されたメッセージに基づいて一括で処理を行います。
署名されたメッセージが有効でない場合、または期限が過ぎている場合、処理は失敗します。

**引数**

- `emoters`
    - エモートを事前に署名したアカウントのアドレスの配列。
- `collections`
    - トークンを含むコレクションのスマートコントラクトのアドレスの配列。
- `tokenIds`
    - エモートされるトークンのIDの配列。
- `emojis`
    - 絵文字のユニコード識別子の配列。
- `states`
    - エモートする（`true`）か取り消す（`false`）かを示す真偽値の配列。
- `deadlines`
    - 署名を提出するための期限となるUNIXタイムスタンプの配列。
- `v`, `r`, `s`
    - ECDSA署名の構成要素の配列。

---

## 署名メッセージのフォーマット

NFTに対する絵文字反応を他の人が代わりに登録するために必要な署名メッセージの形式に関して説明しています。

:::note info
NFTに絵文字で反応を示す人（エモーター）が、その反応をスマートコントラクトに登録するために特定の情報を含むメッセージに署名します。
:::

```javascript
keccak256(
    abi.encode(
        DOMAIN_SEPARATOR,
        collection,
        tokenId,
        emoji,
        state,
        deadline
    )
);
```

このメッセージは以下の要素を含んでいます。

- `DOMAIN_SEPARATOR`
    - エモータブルリポジトリスマートコントラクトのドメインセパレータ。
    - これは、コントラクトの識別子のようなものです。
- `collection`
    - エモートされるトークンを含むコレクションのアドレス。
    - これは、どのNFTコレクションに反応しているかを特定します。
- `tokenId`
    - エモートされるトークンのID。
    - 具体的にどのNFTに反応しているかを示します。
- `emoji`
    - 絵文字のユニコード識別子。
    - どの絵文字で反応するかを示します。
- `state`
    - 絵文字反応を行うか（`true`）、それとも取り消すか（`false`）を示すブール値。
- `deadline`
    - 署名が提出される期限のUNIXタイムスタンプ。
    - 署名が有効な期限を設定します。

`DOMAIN_SEPARATOR`は、「**ERC-7409: Public Non-Fungible Token Emote Repository**」という名前、バージョン「`1`」、ブロックチェーンID、コントラクトのアドレスを組み合わせて生成されます。
これにより、異なるブロックチェーン上でデプロイされたコントラクトは異なるドメインセパレータを持つことになります。

```javascript
keccak256(
    abi.encode(
        "ERC-7409: Public Non-Fungible Token Emote Repository",
        "1",
        block.chainid,
        address(this)
    )
);
```

## Emotableリポジトリのアドレス

Emotableリポジトリのアドレスは事前に決まっていて、そのコントラクトが提供する機能を表すように特別に設計されています。
「**EMOTES**」（絵文字反応）という言葉を連想させる数字「`0x3110735`」で始まるアドレスを持っています。
このアドレスは「`0x3110735F0b8e71455bAe1356a33e428843bCb9A1`」というものです。

:::note info
このアドレスはエモータブルリポジトリスマートコントラクトの「**住所**」のようなもので、このアドレスを使ってコントラクトとやり取りが行われます。
このアドレスの始まりが「**EMOTES**」を思わせるデザインになっているのは、このコントラクトがNFTに対して絵文字で反応する機能（エモート）を扱っているからです。
このようなデザインは、コントラクトの機能をわかりやすく示しています。
:::

# 補足

### カスタム絵文字か、ユニコード指定の絵文字のみか
この提案では、ユニコード識別子（文字列）のみを受け入れます。
これは、標準の絵文字の使用を推奨しながらも、ユニコード標準に含まれない値をカスタム絵文字として使用できることを意味します。
しかし、これらのカスタム絵文字を表示するためには、インターフェースが対応する画像を知っている必要があり、その使用は限定される可能性があります。

### 絵文字を使用した印象の表現
印象をユーザーが提供する文字列や数値で表すことも考えられましたが、絵文字は感情や印象を伝えるのに確立された方法であるため、この提案では絵文字を使用することにしました。

### エモータブル拡張か共通リポジトリか
当初は**ERC721**に準拠したトークン用のエモータブル拡張を作成する予定でしたが、共通リポジトリとすることがより有用であると判断しました。
これにより、新しいトークンだけでなく、提案前から存在する古いトークンにも反エモートできるようになります。

### シングルアクションのみ、マルチアクションのみ、または両方か
シングルアクションのみを含めることも考えられましたが、シングルアクションとマルチアクションの両方を含めることにしました。
これにより、ユーザーは一つのトークンだけでなく、複数のトークンに一度に反応することもできます。

### 他人に代わってエモートする機能
当初は予定していませんでしたが、他人に代わってエモートする機能を追加することが有用であると考え、提案に含めました。
これにより、ユーザーは他人に代わってエモートすることが可能になります。

### 他人に代わってエモートする時の正当性の確保
ECDSA署名を用いることで、ユーザーが他人に代わってエモートすることに同意していることを保証します。
ユーザーはエモートの詳細を含むメッセージに署名し、それを他人が提出することができます。

### トークンに反応する際のチェーンIDの追加
この提案の議論中にチェーンIDをパラメータとして追加することが提案されましたが、追加のコストが発生し、ほとんど使用されないと考え、これを含めることには反対しました。

### 絵文字の表現にbytes4か文字列か
当初は`bytes4`を使用する予定でしたが、絵文字が8バイト以上を使用することがあるため、文字列を使用することにしました。
これにより、将来ユニコード標準に追加されるかもしれない絵文字にも対応できます。

これらの検討により、この提案は**ERC6381**の将来の互換性の問題を解決しています。

# 後方互換性

エモートリポジトリ標準は**ERC721**トークンと完全に互換性があります。
**ERC721**トークンのために開発されている強固なツールや既存のインフラと組み合わせて、エモートリポジトリ標準を利用することができます。

:::note info
エモートリポジトリ標準は**ERC721**トークンとスムーズに連携し、**ERC721**のために用意されているツールや既に構築されているコントラクトの設計と互換性があります。
この互換性により、開発者は既存の**ERC721**ベースのプロジェクトにエモートリポジトリの機能を容易に追加でき、ユーザーにより豊かな体験を提供できるようになります。
:::

# テスト

以下にテストファイルが格納されています。

https://eips.ethereum.org/assets/eip-7409/test/emotableRepository.ts

以下のコマンドでテストを実行できます。

```bash
cd ../assets/eip-7409
npm install
npx hardhat test
```

# 参考実装

以下のファイルに参考実装コードが書かれています。

https://eips.ethereum.org/assets/eip-7409/contracts/EmotableRepository.sol

# セキュリティ考慮事項

エモートリポジトリという新しい提案がユーザーの資産を直接扱わないため、エモートリポジトリとのやり取りでユーザーの資産が危険にさらされることはないです。

他人の代わりにECDSA署名を使ってエモート（絵文字で反応）する機能にはリプレイ攻撃（同じ署名を不正に再利用する攻撃）のリスクがあります。
しかし、署名されるメッセージの形式がこのリスクを防いでいます。
署名に含まれる`DOMAIN_SEPARATOR`は、そのスマートコントラクトがデプロイされたブロックチェーンに固有のもので、したがって署名は他のチェーンでは無効になります。
リプレイ攻撃が試みられた場合、エモートリポジトリはその操作を取り消すはずです。

さらに、署名されたメッセージの再利用に関しても検討する必要があります。
メッセージには署名の有効期限が含まれているため、期限内であれば何度でも再利用できます。
提案では、一つのトークンに対して一つの絵文字での反応しか許可されていないため、署名されたメッセージを悪用してトークンの反応数を不正に増やすことはできません。
しかし、リポジトリを使用するサービスが反応を特定のアクション後に取り消す機能を持つ場合、有効な署名されたメッセージはトークンに再反応するために使用される可能性があります。
このため、リポジトリを利用するサービスは、事前に署名されたメッセージが短期間で無効となるような期限を設定することが推奨されます。

最後に、監査されていないコントラクトを扱う時には注意が必要です。
これは、セキュリティ上のリスクを避けるための一般的な注意喚起です。

# 引用

Bruno Škvorc (@Swader), Steven Pineda (@steven2308), Stevan Bogosavljevic (@stevyhacker), Jan Turk (@ThunderDeliverer), "ERC-7409: Public Non-Fungible Tokens Emote Repository," Ethereum Improvement Proposals, no. 7409, July 2023. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7409.

# 最後に

今回は「**ERC6381**を拡張して、一括処理機能の追加と扱える絵文字を増やす提案している規格である**ERC7409**」についてまとめてきました！
いかがだったでしょうか？

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

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

他の媒体でも情報発信しているのでぜひ他も見ていってください！

https://chaldene.net/

https://zenn.dev/heku

https://mirror.xyz/0xcE77b9fCd390847627c84359fC1Bc02fC78f0e58


https://cardene.notion.site/ERC-EIP-2a03fa3ea33d43baa9ed82288f98d4a9?pvs=4