はじめに
『DApps開発入門』という本や色々記事を書いているかるでねです。
今回は、ERC1155をtransfer
できないSBTにする仕組みを提案しているERC5633についてまとめていきます!
以下にまとめられているものを翻訳・要約・補足しながらまとめていきます。
他にも様々なEIPについてまとめています。
概要
ERC5633は、ERC1155を拡張する提案です。
特徴は、「ソウルバウンド(Soulbound)」かどうかの性質をトークンごとに設定できるようにする点です。
ソウルバウンドとは、一度発行されたトークンが他のアカウントに移動できない性質のことで、譲渡不可能なトークンです。
ERC5633では、1つのコントラクト内でソウルバウンドなNFTとそうでないNFTの両方を扱える仕組みを提案しています。
動機
ゲーム「World of Warcraft(WoW)」に登場する「ソウルバウンドアイテム」からインスピレーションを受けています。
WoWでは、キャラクターが装備した瞬間から他のプレイヤーに渡せなくなるアイテムが存在します。
例えば、「Caliseaのネックレス」というレアなアイテムはソウルバウンドで譲渡できませんが、普通の低レベルのネックレスは譲渡可能だったりします。
Ethereumのコミュニティでも、こうした「譲渡不可なNFT(=ソウルバウンドNFT)」が注目されており、アイテムの種類ごとにその性質を定義できる標準が求められています。
ERC5633により、1つのNFTコントラクトで複数タイプのトークンを管理し、それぞれが「譲渡可能かどうか」を独立して持てるようになります。
例えばゲーム内の装備や称号などを1つの仕組みで管理しやすくなるという利点があります。
ERC5633では、ERC165というインターフェース検出の仕組みを活用します。
ウォレットやアプリケーション側が、あるトークンIDがソウルバウンドかどうかを事前に確認できるようになります。
さらに、もしトークンがソウルバウンドでなければ、通常通り transfer
関数を使って他人に送ることが可能です。
逆にソウルバウンドであれば送ろうとしてもブロックされます。
ERC165については以下の記事を参考にしてください。
このように、開発者はコントラクトレベルでソウルバウンドかどうかの確認ロジックを組み込むことができ、ユーザーにとっても予期せぬトークン移動の失敗を避けられる仕組みになっています。
仕様
// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.0;
interface IERC5633 {
/**
* @dev Emitted when a token type `id` is set or cancel to soulbound, according to `bounded`.
*/
event Soulbound(uint256 indexed id, bool bounded);
/**
* @dev Returns true if a token type `id` is soulbound.
*/
function isSoulbound(uint256 id) external view returns (bool);
}
あるNFTのIDが isSoulbound(uint256 id)
を実行したときに true
を返せば、そのトークンはソウルバウンド(譲渡不可)と見なされます。
つまり、そのIDを持つトークンは他のアカウントに送ることができなくなります。
この場合、そのトークンに対してERC1155で定義されている「transfer
」系の関数はすべて使えなくなります。
正確に言うと、使おうとするとエラーになります。
ただし、mint
(発行)と burn
だけは例外で引き続き使えます。
インターフェースの定義(IERC5633
)
この仕様で使われるインターフェース IERC5633
は以下の2つのイベントと関数を実装する必要があります。
event Soulbound(uint256 id, bool bounded)
特定のトークンIDがソウルバウンドとして設定・解除されたときに発行されるイベントです。
bounded
が true
ならソウルバウンド、false
なら解除されたことを意味します。
function isSoulbound(uint256 id) external view returns (bool)
トークンIDがソウルバウンドかどうかを確認する関数です。
ERC165との連携
このインターフェース IERC5633
を実装するコントラクトは、ERC165の supportsInterface
関数も必ず実装する必要があります。
そして、interfaceID
に 0x911ec470
が渡されたときには、必ず true
を返さなければいけません。
これは「このコントラクトは IERC5633
に対応している」と外部から確認するための仕組みです。
ウォレットや他のコントラクトがそのコントラクトに対して supportsInterface(0x911ec470)
を呼ぶことで、ソウルバウンド対応かどうかが判断できるようになっています。
補足
コントラクト内のトークンが全てデフォルトでソウルバウンドトークンの場合、実装中はisSoulbound(uint256 id)
がデフォルトでtrue
を返す必要があります。
参考実装
// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "./IERC5633.sol";
/**
* @dev Extension of ERC1155 that adds soulbound property per token id.
*
*/
abstract contract ERC5633 is ERC1155, IERC5633 {
mapping(uint256 => bool) private _soulbounds;
/// @dev See {IERC165-supportsInterface}.
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC1155) returns (bool) {
return interfaceId == type(IERC5633).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns true if a token type `id` is soulbound.
*/
function isSoulbound(uint256 id) public view virtual returns (bool) {
return _soulbounds[id];
}
function _setSoulbound(uint256 id, bool soulbound) internal {
_soulbounds[id] = soulbound;
emit Soulbound(id, soulbound);
}
/**
* @dev See {ERC1155-_beforeTokenTransfer}.
*/
function _beforeTokenTransfer(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual override {
super._beforeTokenTransfer(operator, from, to, ids, amounts, data);
for (uint256 i = 0; i < ids.length; ++i) {
if (isSoulbound(ids[i])) {
require(
from == address(0) || to == address(0),
"ERC5633: Soulbound, Non-Transferable"
);
}
}
}
}
引用
HonorLabs (@honorworldio), "ERC-5633: Composable Soulbound NFT, EIP-1155 Extension [DRAFT]," Ethereum Improvement Proposals, no. 5633, September 2022. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-5633.
最後に
今回は「ERC1155をtransfer
できないSBTにする仕組みを提案しているERC5633」についてまとめてきました!
いかがだったでしょうか?
質問などがある方は以下のTwitterのDMなどからお気軽に質問してください!
他の媒体でも情報発信しているのでぜひ他も見ていってください!