🔒

【2023年最新】譲渡不可能なNFT(SBT)の作り方

SBT(SoulBound Token)について

SBT(SoulBound Token)は、アドレスに対して永久的に紐づけられたNFTのことを言います。ざっくりというと譲渡不可なNFTということになります。ERCとしてもしっかりと定義されたためその辺についても追記できればと思います。

【結論】 SBTの実装

ミニマムにSBTを実装する方法を紹介します。以下のgithubからERC5192.solIERC5192.solを含むERC5192フォルダをダウンロードし、デプロイコントラクトと同階層に置きます。
https://github.com/attestate/ERC5192/tree/main/src

そして、以下のコードでSBTを実装することができます。

import { ERC5192 } from "ERC5192/ERC5192.sol";

contract SBT is ERC5192 {
  bool private isLocked;
  constructor(string memory _name, string memory _symbol, bool _isLocked)
    ERC5192(_name, _symbol, _isLocked)
  {
    isLocked = _isLocked;
  }
  function safeMint(address to, uint256 tokenId) external {
    _safeMint(to, tokenId);
    if (isLocked) emit Locked(tokenId);
  }
}

SBT = ERC5192

SBTの規格はERC5192によって定義されています。
SBTとして認識されるための重要なポイントは3つであると考えます。

  • transferメソッドの制限
  • ERC5192のsupportInterfaceの追加
  • view関数であるlocked関数

transferメソッドの制限

SBTの最も直感的で分かりやすいポイントです。checkLockというmodifierを作成し、それぞれのtransfer関数の事前チェックに使用して制限します。SBTの場合はisLocked変数が永続的にfalseのため、transferすることができません。

ERC5192.sol
modifier checkLock() {
  if (isLocked) revert ErrLocked();
  _;
}

function transferFrom(address from, address to, uint256 tokenId)
  public
  override
  checkLock
{
  super.transferFrom(from, to, tokenId);
}

ERC5192のsupportInterfaceの追加

スケーラビリティにおいて重要な部分です。外部に自分がSBTであることを伝達する役割を持っています。

ERC5192.sol
function supportsInterface(bytes4 interfaceId)
  public
  view
  virtual
  override
  returns (bool)
{
  return interfaceId == type(IERC5192).interfaceId
    || super.supportsInterface(interfaceId);
}

view関数であるlocked関数

同じくスケーラビリティにおいて重要な部分です。supportInterfaceは、外部に対してERC5192に準拠していることを知らせ、SBTとして共通のインターフェイスを持っていることを伝えます。locked関数は、それとは少し変わり、特定のtokenIdに対して、そのNFTが譲渡不可であるかを外部から確認できる機能を持っています。

ERC5192.sol
function locked(uint256 tokenId) external view returns (bool) {
  if (!_exists(tokenId)) revert ErrNotFound();
  return isLocked;
}

おすすめの記事

thirdwebを用いてプログラミングを使わずにSBTを発行することができます。
https://zenn.dev/yuki2020/articles/f8bea0a17f5d7b

シンシズモ株式会社

Discussion