はじめに
『DApps開発入門』という本や色々記事を書いているかるでねです。
今回は、NFTを物理的なアイテムと引き換え可能かを判定する仕組みを提案しているERC5560についてまとめていきます!
以下にまとめられているものを翻訳・要約・補足しながらまとめていきます。
他にも様々なEIPについてまとめています。
概要
ERC5560は、ERC721形式のNFTに「引き換え機能(redeem function)」を追加する仕組みを提案しています。 NFTを使って、物理的なモノと交換できるようにしたい発行者向けの機能です。
動機
最近、アーティストや高級アートギャラリー、オークションハウス、ブランドなどが、NFTを通じて物理的な商品を提供するケースが増えています。 例えば、絵画のNFTを持っている人が、その本物の絵を受け取れるようにしたいというようなニーズです。 ERC5560では、NFTが物理的なモノと引き換え可能であること(= redeemable)を明確に示せるようにすることでニーズに応えようとしています。
仕様
import '@openzeppelin/contracts/utils/introspection/ERC165.sol';
/**
* @dev Implementation of Redeemable for ERC-721s
*
*/
interface IRedeemable is ERC165 {
/*
* ERC165 bytes to add to interface array - set in parent contract implementing this standard
*
* bytes4 private constant _INTERFACE_ID_ERC721REDEEM = 0x2f8ca953;
*/
/// @dev This event emits when a token is redeemed.
event Redeem(address indexed from, uint256 indexed tokenId);
/// @notice Returns the redeem status of a token
/// @param tokenId Identifier of the token.
function isRedeemable(uint256 _tokenId) external view returns (bool);
/// @notice Redeeem a token
/// @param tokenId Identifier of the token to redeeem
function redeem(uint256 _tokenId) external;
}ERC721に準拠したNFTコントラクトは、この拡張仕様(Redeemable NFT)を任意で実装できます。 実装することで、NFTが「引き換え可能かどうか」を判定したり、引き換え処理を実行できるようになります。
誰がredeemできるかは発行者が決める
NFTの発行者は、「誰がredeem(引き換え)できるか」を自分で決める必要があります。
redeem関数を誰でも実行できるようにするのではなく、アクセス制御をしっかりと設定することが重要です。
引き換え可能かを確認する方法
誰でもisRedeemableという関数を呼び出して、特定のNFTが引き換え可能かどうかを確認できます。
- 引き換え可能な場合は
trueを返します。 - すでに引き換えられている場合は
falseになります。
外部サービスとの連携
ERC5560に対応した外部サービス(マーケットプレイスなど)は、「Redeemイベント」を使って、NFTの引き換え状態が変わったタイミングを検知することができます。
これにより、引き換え済みのNFTをマーケットで売買させないなどの対応が可能になります。
関数
ERC5560に準拠する場合は、以下の関数やイベントを実装する必要があります。
isRedeemable(uint256 _tokenId)
指定されたNFTが引き換え可能かどうかを返す関数。
redeem(uint256 _tokenId)
NFTを引き換える処理を実行する関数。
event Redeem(address indexed from, uint256 indexed tokenId)
引き換えが行われたときに発行されるイベント。
ERC165
supportsInterfaceという関数を使って、コントラクトがERC5560(IRedeemable)に対応しているかどうかを判定できます。
このとき、引数として 0x2f8ca953 を渡すと true を返すようにする必要があります。
これはIRedeemableの識別子となる値です。
ERC165については以下の記事を参考にしてください。
補足
デフォルトの挙動について
NFTコントラクトをデプロイした直後は、isRedeemable() 関数が常に true を返す状態になっています。
つまり、その時点ではすべてのNFTが「引き換え可能」として扱われます。
また、redeem() 関数は特に制限をつけなければ public(公開)になっており、誰でも実行できてしまいます。
これはセキュリティ上よくないので、引き換え処理を許可する相手を制限することが強く推奨されています。
アクセス制御の推奨方法
誰でも勝手に redeem() を実行できると、本来のNFT保有者以外が引き換えてしまう危険があります。
そこで、以下のような require を使って、実行者がNFTの保有者であることをチェックすることが一般的です。
require(ownerOf(tokenId) == msg.sender, "ERC721Redeemable: You are not the owner of this token");引き換え後の状態
redeem() 関数が正常に実行された後、そのトークンに対して isRedeemable() を呼び出すと false が返るようになります。
これで「既に引き換え済み」という状態がわかります。
Redeemイベント
redeem() が実行されたタイミングでは、必ず以下のイベントを発行する必要があります。
event Redeem(address indexed from, uint256 indexed tokenId);これにより、外部のサービスやDAppが「誰がどのNFTを引き換えたのか」をリアルタイムで追跡できるようになります。 例えば、NFTのマーケットプレイス側で「このNFTはもう使われたから販売リストから外す」といった処理を実行できます。
互換性
ERC5560は、ERC721と完全に互換性があります。
参考実装
contract ERC721Redeemable is ERC721, Redeemable {
constructor(string memory name, string memory symbol) ERC721(name, symbol) {
}
function isRedeemable(uint256 tokenId) public view virtual override returns (bool) {
require(_exists(tokenId), "ERC721Redeemable: Redeem query for nonexistent token");
return super.isRedeemable(tokenId);
}
function redeem(uint256 tokenId) public virtual override {
require(_exists(tokenId), "ERC721Redeemable: Redeem query for nonexistent token");
require(ownerOf(tokenId) == msg.sender, "ERC721Redeemable: You are not the owner of this token");
super.redeem(tokenId);
}
function supportsInterface(bytes4 interfaceId) public view override(ERC721, Redeemable) returns (bool) {
return super.supportsInterface(interfaceId);
}
}引用
Olivier Fernandez (@fernandezOli), Frédéric Le Coidic (@FredLC29), Julien Béranger (@julienbrg), "ERC-5560: Redeemable NFTs [DRAFT]," Ethereum Improvement Proposals, no. 5560, August 2022. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-5560.
最後に
今回は「NFTを物理的なアイテムと引き換え可能かを判定する仕組みを提案しているERC5560」についてまとめてきました! いかがだったでしょうか?
質問などがある方は以下のTwitterのDMなどからお気軽に質問してください!
他の媒体でも情報発信しているのでぜひ他も見ていってください!

