はじめに

『DApps開発入門』という本や色々記事を書いているかるでねです。

今回は、ブロックチェーン上のNFTに紐づく特典や引換権を安全に行使する仕組みを提案しているERC7765についてまとめていきます!

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

他にも様々なEIP・BIP・SLIP・CAIP・ENSIP・RFC・ACPについてまとめています。

概要

ERC7765は、現実世界の資産(Real World Asset, RWA)に紐づいたNFTが「権利」や「特典(Privileges)」を持つことを前提に、それらをオンチェーンで扱うための標準インターフェースを定義する規格です。 ここでいう権利とは、単なるデジタル上の所有権ではなく、NFTの保有者が現実世界で実際に行使できる権利や利益を指します。

例えば、ブロックチェーン上でスニーカーがNFTとして販売され、そのNFTを保有している人が、現実世界で実物のスニーカーを受け取れる場合を考えます。 このときNFTは単なるデジタルアートではなく、「現物を受け取る権利」を表す証明書として機能します。 ERC7765は、このような「現実世界で行使できる権利が結びついたNFT」の共通インターフェースを定義するものです。

重要なのは、権利の行使自体は現実世界(オフチェーン)で起こりますが、その意思表示や状態管理はブロックチェーン上(オンチェーン)で行われる点です。 NFTの保有者がトランザクションを送信することで「この権利を行使する」という意思を明示し、その後の物流や本人確認、引き換え処理などの現実世界の手続きへと接続されます。

動機

現実世界の資産をNFTとして表現するケースでは、単なる所有証明だけでなく、「何かを受け取る」、「サービスを利用する」、「交換する」といった権利が付随することが多くあります。 しかし、これらの権利の扱い方はプロジェクトごとに実装が異なり、ウォレットやマーケットプレイス、外部サービスとの連携が難しい状況でした。

ERC7765が想定する流れは以下です。

  1. 現実の商品やサービスをNFTとしてオンチェーンで販売します。
  2. NFTの保有者は、特定の関数を呼び出すことで「権利を行使する」というトランザクションを送信します。
  3. そのオンチェーンの操作をトリガーとして、オフチェーンのシステムが動作し、実物の発送やサービス提供が行われます。

このように、オンチェーンの状態とオフチェーンの実世界の処理を一対一で対応させることで、「ブロックチェーン上の操作が、そのまま現実世界の行動につながる」構造を作れます。

具体例として、NFTで販売された靴を考えると、NFTの保有者は「引き換え権の行使」をオンチェーンで宣言し、その結果として倉庫システムや配送システムが連携し、実物の靴が発送されます。 このとき、どのNFTがどの権利を持ち、どの操作でその権利が消費されるのかが標準化されていなければ、サービス間の相互運用は困難になります。

ERC7765が標準インターフェースを定めることで、以下が可能になります。

項目 内容
サービス間の相互運用性 ウォレット、マーケットプレイス、バックエンドが同じ仕様で権利行使を扱えます。
UIの共通化 「引き換え」、「利用する」といった操作を汎用UIで表現できます。
コントラクト連携 他のスマートコントラクトが、権利の状態や行使状況を安全に参照できます。

このようにERC7765は、「NFTで現実資産を表現する」だけでなく、「その資産に紐づく権利を、オンチェーン操作として正式に定義して現実世界の処理と確実に結びつける」ことを目的とした規格です。

仕様

ERC721との関係

ERC7765は、NFTの基盤としてERC721をそのまま継承します。

ERC721については以下の記事を参考にして下さい。

具体的には以下をそのまま利用します。

項目 内容
所有権管理 transferFrom / safeTransferFrom などの転送ロジックはERC721準拠です。
承認機構 approve / setApprovalForAll もERC721の仕様どおりです。
メタデータ name、symbol、tokenURI はERC721 Metadata拡張を継承します。

つまり ERC7765 は「権利付きNFT」を実現するために、ERC721の上に「権利行使用インターフェース」を追加した規格です。

IERC7765インターフェース

IERC7765.sol
pragma solidity >=0.7.0 <0.9.0;

/// @title ERC-7765 Privileged Non-Fungible Tokens Tied To Real World Assets
/// @dev See https://eips.ethereum.org/EIPS/eip-7765
interface IERC7765 /* is IERC721, IERC165 */ {

    /// @notice This event emitted when a specific privilege of a token is successfully exercised.
    /// @param _operator  the address who exercised the privilege.
    /// @param _to  the address to benefit from the privilege.
    /// @param _tokenId  the NFT tokenID.
    /// @param _privilegeId  the ID of the privileges.
    event PrivilegeExercised(
        address indexed _operator,
        address indexed _to,
        uint256 indexed _tokenId,
        uint256 _privilegeId
    );

    /// @notice This function exercise a specific privilege of a token.
    /// @dev Throws if `_privilegeId` is not a valid privilegeId.
    /// @param _to  the address to benefit from the privilege.
    /// @param _tokenId  the NFT tokenID.
    /// @param _privilegeId  the ID of the privileges.
    /// @param _data  extra data passed in for extra message or future extension.
    function exercisePrivilege(
        address _to,
        uint256 _tokenId,
        uint256 _privilegeId,
        bytes calldata _data
    ) external;

    /// @notice This function is to check whether a specific privilege of a token can be exercised.
    /// @dev Throws if `_privilegeId` is not a valid privilegeId.
    /// @param _to  the address to benefit from the privilege.
    /// @param _tokenId  the NFT tokenID.
    /// @param _privilegeId  the ID of the privileges.
    function isExercisable(
        address _to,
        uint256 _tokenId,
        uint256 _privilegeId
    ) external view returns (bool _exercisable);

    /// @notice This function is to check whether a specific privilege of a token has been exercised.
    /// @dev Throws if `_privilegeId` is not a valid privilegeId.
    /// @param _to  the address to benefit from the privilege.
    /// @param _tokenId  the NFT tokenID.
    /// @param _privilegeId  the ID of the privileges.
    function isExercised(
        address _to,
        uint256 _tokenId,
        uint256 _privilegeId
    ) external view returns (bool _exercised);

    /// @notice This function is to list all privilegeIds of a token.
    /// @param _tokenId  the NFT tokenID.
    function getPrivilegeIds(
        uint256 _tokenId
    ) external view returns (uint256[] memory privilegeIds);

}

ERC7765に準拠するコントラクトは、必ずこのインターフェースを実装します。 内部的にはERC721とERC165(インターフェース判定規格)を継承する前提です。

ERC165については以下の記事を参考にして下さい。

イベント

PrivilegeExercised
javascript
event PrivilegeExercised(
    address indexed _operator,
    address indexed _to,
    uint256 indexed _tokenId,
    uint256 _privilegeId
);

特定のNFTに紐づく権利が実際に行使されたときに発行されるイベント。 オンチェーンで「権利行使」が成功したことを外部システムが検知するためのフックです。 物流システムや認証システムはこのイベントを監視し、現実世界の処理を開始します。

パラメータ

名前 内容
_operator 実際に権利行使トランザクションを送信したアドレスです。
_to 権利の利益を受け取るアドレスです(本人以外も指定可能)。
_tokenId 対象となるNFTのIDです。
_privilegeId 行使された権利の識別子です。

関数

exercisePrivilege
javascript
function exercisePrivilege(
    address _to,
    uint256 _tokenId,
    uint256 _privilegeId,
    bytes calldata _data
) external;

NFTに紐づく特定の権利を実際に行使するための関数。 NFT保有者、もしくは承認されたアドレスが呼び出します。 成功時には必ず PrivilegeExercised イベントが発行され、オフチェーン処理の起点となります。 _privilegeId が無効な場合はリバートします。

引数

名前 内容
_to 権利の恩恵を受けるアドレスです。
_tokenId 権利を行使するNFTのIDです。
_privilegeId 行使対象の権利IDです。
_data 将来拡張やメッセージ連携用の任意データです。
isExercisable
javascript
function isExercisable(
    address _to,
    uint256 _tokenId,
    uint256 _privilegeId
) external view returns (bool _exercisable);

指定した権利が現在行使可能かどうかを判定する関数。 有効期限切れ、すでに使用済み、本人確認未完了など、実装側の条件に基づいて true / false を返します。

戻り値

名前 内容
_exercisable 現在行使可能であれば true です。
isExercised
javascript
function isExercised(
    address _to,
    uint256 _tokenId,
    uint256 _privilegeId
) external view returns (bool _exercised);

指定した権利がすでに行使済みかどうかを確認する関数。 一度限りの引き換え権などで、再利用防止のために利用されます。

getPrivilegeIds
javascript
function getPrivilegeIds(
    uint256 _tokenId
) external view returns (uint256[] memory privilegeIds);

特定NFTに紐づくすべての権利ID一覧を取得する関数。 UIやバックエンドが「このNFTで何ができるか」を一覧表示するための基礎情報になります。

任意拡張:権利メタデータ(IERC7765Metadata)

IERC7765Metadata.sol
pragma solidity >=0.7.0 <0.9.0;

/// @title ERC-7765 Privileged Non-Fungible Tokens Tied To Real World Assets, optional metadata extension
/// @dev See https://eips.ethereum.org/EIPS/eip-7765
interface IERC7765Metadata /* is IERC7765 */ {

    /// @notice A distinct Uniform Resource Identifier (URI) for a given privilegeId.
    /// @dev Throws if `_privilegeId` is not a valid privilegeId. URIs are defined in RFC
    ///  3986. The URI may point to a JSON file that conforms to the "ERC-7765
    ///  Metadata JSON Schema".
    function privilegeURI(uint256 _privilegeId) external view returns (string memory);

}

ERC7765は、権利ごとのメタデータURIを定義する拡張仕様を持ちます。 この拡張はオプションですが、実装する場合は必ずIERC7765も同時に実装します。

権利メタデータJSONスキーマ

javascript
{
    "title": "Privilege Metadata",
    "type": "object",
    "properties": {
        "name": {
            "type": "string",
            "description": "Identifies the specific privilege."
        },
        "description": {
            "type": "string",
            "description": "Describes the specific privilege."
        },
        "resource": {
            "type": "string",
            "description": "A URI pointing to a resource representing the specific privilege."
        }
    }
}

このJSONは、ERC721 tokenURIと同様の役割を、権利単位で提供します。

フィールド 意味
name 権利の名称です(例:Physical Shoe Redemption)。
description 権利の内容説明です(例:実物スニーカー引換権)。
resource 利用規約や引換ページなどへのURIです。

全体構造の関係図

flowchart LR
    NFT[ERC721 NFT]
    Privilege[Privilege ID]
    Metadata[Privilege Metadata JSON]
    Offchain[Real World Process]

    NFT --> Privilege
    Privilege -->|exercisePrivilege| Offchain
    Privilege --> Metadata
    Offchain -->|emit| Event[PrivilegeExercised]

補足

権利行使をイベントで確定させる理由

ERC7765では、権利が実際に行使されたことをオンチェーンで確定させる手段として PrivilegeExercised イベントを定義しています。 このイベントが発行された時点で、「NFTの保有者(または許可された実行者)が、その権利を行使する意思を正式に表明した」ことがブロックチェーン上で証明されます。

これにより、オフチェーン側のシステムはこのイベントを監視することで、以下を正確に把握できます。

  • いつ
  • 誰のNFTの
  • どの権利が
  • 誰のために行使されたか

その結果、倉庫システムによる発送、本人確認後のサービス提供、ライセンス発行など、現実世界での処理を安全にトリガーできます。

つまり、ERC7765におけるイベントは「現実世界の処理を開始してよいという確定シグナル」として機能します。

_to パラメータを持たせている理由

exercisePrivilege、isExercisable、isExercised の各関数に _to(権利の受益者アドレス)が含まれているのは、NFTの所有者やトランザクション送信者とは別の第三者が、権利の利益を受け取れるようにするためです。

例えば以下のようなケースを想定しています。

ケース 説明
ギフト NFT所有者が、実物商品を友人の住所宛に送る場合。
法人利用 会社が保有するNFTの権利を、社員個人に割り当てる場合。
委任行使 ウォレット操作代行サービスが、ユーザーの代わりに権利を実行する場合。

ERC7765は、「誰が権利を実行できるか」、「誰のために実行できるか」を仕様レベルで固定していません。 それらの権限設計は、コントラクト開発者がユースケースに応じて自由に定義できる構造になっています。

_data フィールドを用意している理由

exercisePrivilege に含まれる _data は、追加情報や将来拡張のための汎用バイト列です。

このフィールドを使うことで、以下のような拡張が可能になります。

  • 注文番号、配送指示、KYCトークンなどの付加情報の埋め込み
  • オンチェーン完結型の権利行使(例:トークン配布、エアドロップ)
  • 将来の仕様拡張に対する後方互換性の確保

特に、権利の行使結果がオンチェーンで完結する場合(例:NFTを使ってステーブルコインを受け取るなど)は、_data を用いて処理条件やメモ情報を一緒に渡せます。

isExercisable と isExercised の役割

これらの関数は、UIや外部サービスが権利の状態を事前確認するための読み取り専用インターフェースです。

関数 役割
isExercisable その権利が今すぐ行使可能かどうかを判定します。
isExercised その権利がすでに行使済みかどうかを判定します。

例えば、以下の条件をスマートコントラクト側で判定し、フロントエンドはそれに基づいて「引き換え可能」、「引き換え済み」といった表示を行えます。

  • 有効期限切れ
  • すでに一度使用済み
  • 本人確認が未完了

互換性

ERC721との完全互換

ERC7765はERC721を拡張する形で設計されており、既存のNFTエコシステムとの互換性を壊しません。

具体的には、以下の拡張とも完全に共存できます。

拡張規格 内容
IERC721Metadata name、symbol、tokenURI によるメタデータ管理です。
IERC721Enumerable totalSupply、tokenOfOwnerByIndex などの列挙機能です。

そのため、ERC7765対応NFTは、以下をそのまま取り扱えます。

  • 既存のNFTマーケットプレイス
  • ウォレット
  • インデクサ
  • 可視化ツール

追加されるのは「権利行使用インターフェース」だけで、NFTとしての基本的な振る舞いはERC721と完全に同一です。

設計思想としての位置づけ

ERC7765は、「ERC721の互換性を維持したまま、現実世界の権利行使という新しい意味層を追加する」ことを目的とした拡張規格です。

その結果、以下の構造になっています。

  • 既存インフラを壊さずにRWA連携が可能
  • 権利管理だけを標準化し、業務ロジックは自由設計
  • 将来のDeFi、ID、物流、チケット、ライセンス用途への拡張が容易

参考実装

引用

frank (@frankmint2024) frank@mintchain.io, "ERC-7765: Privileged Non-Fungible Tokens Tied To RWA [DRAFT]," Ethereum Improvement Proposals, no. 7765, August 2024. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7765.

最後に

今回は「ブロックチェーン上のNFTに紐づく特典や引換権を安全に行使する仕組みを提案しているERC7765」についてまとめてきました! いかがだったでしょうか?

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

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