はじめに
初めまして。
CryptoGamesというブロックチェーンゲーム企業でエンジニアをしている cardene(かるでね) です!
スマートコントラクトを書いたり、フロントエンド・バックエンド・インフラと幅広く触れています。
代表的なゲームはクリプトスペルズというブロックチェーンゲームです。
今回は、イベントチケットなどのNFTの消費を管理できるインターフェースを提供するERC2135についてまとめていきます!
以下にまとめられているものをChatGPTも使用しながら、翻訳・要約・補足してまとめていきます。
概要
このEIPは、Ethereum上でデジタルアセットに「消費可能」というマークをつけ、「消費」に対応するためのインターフェースを提供することを目的としています。
これにより、様々なデジタルアセットに対して、消費行為やその他のアクションに対応する標準化された方法を定義することが可能になります。
動機
デジタルアセットが一部の状態変化によって消費される場合があります。
例えば、コンサートチケットです。
チケット保持者がコンサート会場に入場すると、そのチケットは消費されたと見なされます。
このような消費行為に対して、一貫性のある方法を提供することが必要とされています。
一貫性がないと以下のような懸念が生じます。
不正な消費
不正な行為や二重支払いのリスクが高まります。
例えば、同じアセットを複数回消費できるといった不正な操作が行われる可能性があります。
予測性の欠如
消費の方法や条件が一貫していない場合、ユーザーやコントラクトがデジタルアセットの挙動を予測することが困難になります。
これは予期せぬ結果やトラブルの原因となります。
エコシステムの混乱
デジタルアセットの消費に関する様々な方法が存在する場合、エコシステム内のアプリケーションやコントラクト間の相互運用性が低下し、混乱が生じる可能性があります。
これは開発者やユーザーの体験を損なうことになります。
セキュリティ上のリスク
一貫性のない消費方法は、デジタルアセットのセキュリティ上の脆弱性をもたらす可能性があります。
セキュリティが不十分な消費方法を利用することで、アセットが不正に利用されたり、攻撃者による悪意のある行為の対象になる可能性があります。
法的・規制上の問題
特定のデジタルアセットには法的な制約や規制が存在する場合があります。
一貫性がない消とこれらの法的・規制上の問題に対処することを困難にする可能性があります。
標準的なインターフェースを持つことにより、サービス、クライアント、UI、コントラクト間の機能が相互運用可能となります。
つまり、異なるアプリケーションやコントラクトがこのインターフェースに準拠することで、デジタルアセットの消費に関連する処理や情報のやり取りが容易になります。
これにより、シームレスなエコシステムが形成され、デジタルアセットをより便利に活用することができるでしょう。
このようなEIPは、ブロックチェーン技術の進化と共に、さまざまなデジタルアセットの管理や取引において重要な役割を果たすことが期待されています。それに伴い、開発者やプロジェクトが共通のルールとインターフェースに基づいて作業できるため、効率的なエコシステムの構築に寄与すると言えます。
仕様
このEIPに準拠するコントラクトは、以下のインターフェイスを実装する。
pragma solidity >=0.7.0 <0.9.0;
interface IERC2135 {
function consume(
address _consumer,
uint256 _assetId,
uint256 _amount,
bytes calldata _data
) external returns (bool _success);
function isConsumableBy(
address _consumer,
uint256 _assetId,
uint256 _amount
) external view returns (bool _consumable);
or future extension.
event OnConsumption(
address indexed consumer,
uint256 indexed assetId,
uint256 amount,
bytes data
);
}
consume
トークンの消費を実行をする関数。
消費が成功した場合は、true
を返します。
parameter
-
_consumer
- トークンを消費するアドレス。
-
_assetId
- 消費されるNFTアセットのトークンID。
-
_amount
- 消費されるアセットの量。
-
_data
- 任意の追加データ。
isConsumableBy
指定されたトークンが指定された量で消費可能かどうかをチェックする関数。
消費可能な場合はtrue
を返します。
parameter
-
_consumer
- トークンを消費するアドレス。
-
_assetId
- 消費されるNFTアセットのトークンID。
-
_amount
- 消費されるアセットの量。
OnConsumption
トークンの消費が成功した場合に発行されるイベント。
消費されたトークンの情報や任意の追加データが含まれます。
parameter
-
_consumer
- トークンを消費するアドレス。
-
_assetId
- 消費されるNFTアセットのトークンID。
-
_amount
- 消費されるアセットの量。
-
_data
- 任意の追加データ。
仕様の補足
ERC721やERC1155というイーサリアムのトークン規格は、非代替可能トークン(NFT)や複数のトークンをまとめて管理するための標準化された方法を提供します。
これらの規格に準拠したコントラクトが存在する場合、消費が行われた際にはいくつかのイベントが発行されます。
ERC721については以下を参考にしてください。
ERC1155については以下を参考にしてください。
-
Transfer
イベント /TransferSingle
イベント:
ERC721やERC1155では、トークンの所有権が変更された場合、Transfer
イベントまたはTransferSingle
イベントが発行されます。
Transfer
イベントは、ERC721の単一のトークンが所有者間で移動する場合に使用されます。
一方、TransferSingle
イベントは、ERC1155の複数のトークンの所有者が一括して変更される場合に使用されます。
-
OnConsumption
イベント:
ERC2135で定義されたOnConsumption
イベントは、トークンの消費が成功した場合に発行されます。
つまり、トークンが消費されたことを示すイベントです。
ERC721やERC1155に準拠したコントラクトのconsume
メソッドが成功すると、次のようなフローになります。
- トークンが消費されたことを示す
OnConsumption
イベントが発行されます。 - トークンの所有権が変更され、
Transfer
イベントまたはTransferSingle
イベントが発行されます。- このとき、トークンは現在の所有者から
0
アドレスに移動したかのように振る舞います。
- このとき、トークンは現在の所有者から
これにより、他のコントラクトやアプリケーションがこれらのイベントを監視してトークンの状態変化を追跡できるようになります。
例えば、デジタルアセットを所有しているユーザーがそれを消費した場合、他のアプリケーションはそれに対応して何らかのアクションを起こすことができます。
また、トークンの移動と消費に関する情報が正確に記録されることで、エコシステム全体の一貫性と相互運用性が確保されます。
補足
このEIPでは、デジタルアセットの「消費」に関連するアクションを実行するためのインターフェースが提案されています。
しかし、消費が行われる具体的な条件や消費を実行する権限については仮定していません。
これは、様々なアセットや使用ケースに対応できる柔軟性を持たせるためです。
具体的な理由として以下が挙げられます。
-
汎用性の確保
消費に関連する条件や権限は、プロジェクトや使用ケースによって異なる場合があります。
このEIPは、特定の制約を設けずに汎用的なインターフェースを提供することで、様々なアセットに対応できるようになっています。 -
ERC721やERC1155との互換性
アセットの識別にはuint256
のアセットIDが使用されるため、ERC721のアセットIDとの互換性を持たせることが考慮されています。
これにより、既存のERC721やERC1155コントラクトとも容易に統合できるようになります。 -
拡張性の考慮
このEIPでは、関数やイベントの追加による拡張性を重視しています。
例えば、_data
フィールドの追加は、将来的な機能拡張や追加情報の付与を容易にします。 -
シンプルなデザイン
このEIPは、消費可能なアセットの作成に関連する機能やイベントを含めないシンプルなデザインになっています。
これは、作成に関する具体的な使用ケースに応じた機能を他の標準で追加することを想定しているためです。
例えば、あるプロジェクトでは、特定のアセットを作成する際には特定の条件が必要とされるかもしれません。
また別のプロジェクトでは、作成されるアセットに特定の属性情報やメタデータが必要になる場合があります。
このように、アセットの作成にはそれぞれ異なる要件や情報が関連付けられることがあります。
このEIPは消費に焦点を当て、作成に関する具体的な機能は別の標準として追加することを想定しています。
また、このインターフェースにはアセットに関連するメタデータも含まれていません。
メタデータは、別個の拡張インターフェースを使用して必要に応じて追加できるようになっています。
このEIPでは、消費アクションに関するインターフェースを提供していますが、消費対象のアセットに関連する「メタデータ」は、このインターフェースに含まれていません。
しかし、必要な場合は「メタデータ」を扱うための別個の拡張インターフェースを使用することができるようになっています。
では、「メタデータ」とは何でしょうか?
メタデータとは、アセットに関する追加の情報や属性情報のことを指します。
例えば、あるNFT(非代替可能トークン)があったとして、そのNFTが何を表しているかを説明するテキストや画像、作成者の情報などが「メタデータ」に該当します。
このEIPでは、「メタデータ」を直接的に扱う機能は提供されていませんが、必要に応じて拡張インターフェースを使用して「メタデータ」を追加できるようになっています。
つまり、アセットの作成者や利用者が「メタデータ」を追加したい場合、別個の拡張インターフェースを作成して、そこに「メタデータ」に関する機能を定義することができるのです。
これにより、アセットに関連する情報を柔軟に拡張できるようになります。
例えば、あるアプリケーションが特定のアセットに対して「メタデータ」を利用してさらなる情報を提供したい場合、そのアプリケーションは別途拡張インターフェースを実装し、必要な「メタデータ」に対する処理をそこで行うことができるのです。
このように、「メタデータ」は消費アクションに直接的には関係しないが、必要な場合は別個の拡張インターフェースを利用して追加することができる仕組みが提供されています。
これにより、アセットに関する情報をさまざまな方法で管理・表示できるようになります。
さらに、consume
関数とisConsumableBy
関数にaddress
型のconsumer
を含めることで、アセットの消費者を指定する柔軟性を持たせています。
これにより、トランザクションのイニシエータ以外の別のユーザーがアセットを消費できるようになります。
このEIPでは、アセットの「消費」に関するインターフェースを定義していますが、その中で「消費」に特定のユーザーを制限することはしていません。
つまり、トランザクションのイニシエータ(トランザクションを発行したユーザー)以外の別のユーザーも、アセットを消費することができるようになります。
これは、「consume
」関数および「isConsumableBy
」関数にaddress
型の「consumer
」パラメータが含まれていることにより実現されています。
例えば、あるアセットがNFTとしてERC721に準拠しているとします。
通常、ERC721の場合、特定のNFTを所有しているアドレス(トランザクションのイニシエータ)以外のユーザーは、そのNFTを送付したり変更したりすることはできません。
しかし、このEIPにより、「consume
」関数の「consumer
」パラメータに他のユーザーのアドレスを指定することで、そのユーザーもアセットを消費することができます。
つまり、トランザクションのイニシエータ以外の別のユーザーがアセットを消費できるようになるのです。
これにより、アセットの消費を特定のユーザーに制限せず、広く利用可能にすることができます。
たとえば、あるアプリケーションが特定のNFTを保有しているユーザー以外にもアセットの消費を許可したい場合、このEIPに従って「consumer
」パラメータを指定することで、そのような機能を実現できるのです。
この柔軟性により、アセットの消費が特定のユーザーに制約されず、より多様な使用ケースやアプリケーションに対応できるようになります。
最後に、ERC721やERC1155だけでなく、他のトークン標準(ERC20、ERC777)やERC1155のFungible Tokenとも互換性があるように設計されています。
これにより、さまざまなトークンの種類に対応する柔軟性があります。
テストケース
describe("Consumption", function () {
it("Should consume when minted", async function () {
const fakeTokenId = "0x1234";
const { contract, addr1 } = await loadFixture(deployFixture);
await contract.safeMint(addr1.address, fakeTokenId);
expect(await contract.balanceOf(addr1.address)).to.equal(1);
expect(await contract.ownerOf(fakeTokenId)).to.equal(addr1.address);
expect(await contract.isConsumableBy(addr1.address, fakeTokenId, 1)).to.be.true;
const tx = await contract.consume(addr1.address, fakeTokenId, 1, []);
const receipt = await tx.wait();
const events = receipt.events.filter((x: any) => { return x.event == "OnConsumption" });
expect(events.length).to.equal(1);
expect(events[0].args.consumer).to.equal(addr1.address);
expect(events[0].args.assetId).to.equal(fakeTokenId);
expect(events[0].args.amount).to.equal(1);
expect(await contract.balanceOf(addr1.address)).to.equal(0);
await expect(contract.ownerOf(fakeTokenId))
.to.be.rejectedWith('ERC721: invalid token ID');
await expect(contract.isConsumableBy(addr1.address, fakeTokenId, 1))
.to.be.rejectedWith('ERC721: invalid token ID');
});
});
describe("EIP-165 Identifier", function () {
it("Should match", async function () {
const { contract } = await loadFixture(deployFixture);
expect(await contract.get165()).to.equal("0xdd691946");
expect(await contract.supportsInterface("0xdd691946")).to.be.true;
});
});
参考実装
アドレス0x3682bcD67b8A5c0257Ab163a226fBe07BF46379B
コントラクトがGoerliテストネットにデプロイされています。
セキュリティに関する考慮事項
トークンの消費による残高変更への注意
このEIPに準拠したコントラクトは、トークンが消費された際の残高変更に注意する必要があります。
消費アクションが行われると、アセット(トークン)の所有者が変わる場合があります。
そのため、消費アクションが正しく行われた場合には、トークンの残高を適切に変更する必要があります。
特に非代替可能トークン(NFT)の場合、一つのトークンを複数のアカウントが同時に所有することができないため、消費アクションによる残高変更は慎重に行われるべきです。
コントラクトの一時停止と消費可能性の一貫性
コントラクトが一時停止される場合や、特定のユーザーがトークンの送付を制限される場合、消費可能性に関連する制約も適切に処理されるべきです。
例えば、一時停止中はトークンの消費ができないようにするなど、トークンの消費とコントラクトの状態変更が一貫していることが重要です。
consumeメソッドのアクセス制御
このEIPに準拠したコントラクトは、自分自身の使用ケースにおいて、どのEOA(外部所有者アカウント)またはコントラクトアカウントがconsume
メソッドを開始できるかを慎重に定義する必要があります。
誰がトークンを消費できるかは、プロジェクトやアプリケーションの要件によって異なる場合があります。
適切なアクセス制御を行わないと、不正なアクションやセキュリティ上のリスクが発生する可能性があります。
セキュリティ監査とテスト
消費アクションに関連するセキュリティは非常に重要です。
コントラクトのコードやアクセス制御を十分に監査し、セキュリティ上の問題がないかを確認するためにセキュリティ監査を実施することが推奨されます。
また、適切なテストを行って、消費関連の機能が予想どおりに機能していることを確認することも重要です。
これらのセキュリティに関する考慮事項を適切に対応して、準拠したコントラクトの安全性と信頼性を確保することが重要です。
セキュリティへの配慮が不十分な場合、悪意ある攻撃やトークンの不正な消費などの問題が発生する可能性があるため、慎重な対応が必要です。
引用
Zainan Victor Zhou (@xinbenlv), "ERC-2135: Consumable Interface (Tickets, etc)," Ethereum Improvement Proposals, no. 2135, June 2019. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-2135.
最後に
今回は「イベントチケットなどのNFTの消費を管理できるインターフェースを提供するERC2135」についてまとめてきました!
いかがだったでしょうか?
質問などがある方は以下のTwitterのDMなどからお気軽に質問してください!
採用強化中!
CryptoGamesでは一緒に働く仲間を大募集中です。
この記事で書いた自分の経験からもわかるように、裁量権を持って働くことができて一気に成長できる環境です。
「ブロックチェーンやWeb3、NFTに興味がある」、「スマートコントラクトの開発に携わりたい」など、少しでも興味を持っている方はまずはお話ししましょう!
ぜひTwitterのDMか上記Wantedlyから連絡ください!