ブロックチェーン学習ロードマップ

ブロックチェーン上のトークン規格:ERC-20, ERC-721, ERC-1155の技術とスマートコントラクト連携

Tags: トークン規格, スマートコントラクト, ERC-20, ERC-721, ERC-1155

はじめに:なぜトークン規格が必要なのか

ブロックチェーン技術の応用分野として、デジタルアセット、特に「トークン」の発行と流通は非常に重要な要素です。仮想通貨(暗号資産)はもちろんのこと、ステーブルコイン、ガバナンストークン、非代替性トークン(NFT)など、様々な種類のトークンが存在します。

これらのトークンは、多くの場合スマートコントラクトによって管理されています。異なるアプリケーション(分散型取引所、ウォレット、ゲームなど)がこれらのトークンを問題なく扱えるようにするためには、トークンが共通の「仕様」や「インターフェース」に従っている必要があります。これは、Web開発において、異なるサービスが共通のAPI仕様に準拠することで連携しやすくなるのと同様の考え方です。

この「共通の仕様」を提供するのが「トークン規格」です。主要なブロックチェーンプラットフォームであるEthereumにおいては、Ethereum Request for Comment(ERC)と呼ばれる規格群が提案され、広く採用されています。本記事では、特に代表的な3つのトークン規格、ERC-20、ERC-721、ERC-1155の技術的な仕組み、役割、そしてスマートコントラクト開発における連携について解説します。

トークン規格の技術的な役割と目的

トークン規格は、スマートコントラクトが特定の機能をどのように実装すべきか、どのような関数やイベントを提供すべきかを定義したものです。これにより、以下のような技術的な利点が生まれます。

主要なトークン規格の技術詳細

ここでは、最も広く利用されている3つのトークン規格について、その特徴と技術的な定義を解説します。

ERC-20: 代替可能トークンの標準

ERC-20は、代替可能(Fungible)なトークンのための標準規格です。代替可能とは、どの単位も他の単位と全く同じ価値を持つ性質を指します。法定通貨やビットコインのような仮想通貨が代表的な例です。1枚の1000円札は別の1000円札と区別されずに交換できます。

ERC-20規格では、トークンを管理するスマートコントラクトが実装すべき主要な関数とイベントが定義されています。以下に、その技術的な要素の一部を示します(Solidity言語のインターフェース定義をイメージしてください)。

interface IERC20 {
    // イベント
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);

    // 関数
    function totalSupply() external view returns (uint256); // 発行されている総トークン数を返す
    function balanceOf(address account) external view returns (uint256); // 指定されたアカウントの残高を返す
    function transfer(address to, uint256 value) external returns (bool); // 呼び出し元から指定アドレスへトークンを転送する
    function allowance(address owner, address spender) external view returns (uint256); // ownerがspenderに代理で使えるトークン上限額を返す
    function approve(address spender, uint256 value) external returns (bool); // spenderが呼び出し元のアカウントから最大valueまで代理転送することを許可する
    function transferFrom(address from, address to, uint256 value) external returns (bool); // fromからtoへ、代理としてトークンを転送する (allowanceが必要)

    // オプション関数(多くの場合実装される)
    // function name() external view returns (string memory); // トークン名を返す
    // function symbol() external view returns (string memory); // トークンシンボルを返す
    // function decimals() external view returns (uint8); // 小数点以下の桁数を返す
}

ERC-20トークンコントラクトは、これらのインターフェースで定義された関数を実装することで、外部からのトークン操作リクエストに応答します。例えば、transfer関数は、トランザクションの送信者(msg.sender)の残高を減らし、指定された宛先アドレスの残高を増やすロジックを内部に持ちます。approvetransferFromの組み合わせは、第三者(例:分散型取引所のスマートコントラクト)がユーザーの代わりにトークンを移動させることを可能にする仕組みです。

ERC-721: 代替不可能トークン(NFT)の標準

ERC-721は、代替不可能(Non-Fungible)なトークンのための標準規格です。代替不可能とは、一つ一つが固有の性質を持ち、他のものと交換できない性質を指します。デジタルアート、ゲーム内アイテム、不動産の権利証などが例として挙げられます。

ERC-721トークンコントラクトは、個々のトークンが一意のID(tokenId)を持つことを前提としています。規格では、各tokenIdが誰に所有されているかを管理し、その所有権を安全に移転するための関数が定義されています。

interface IERC721 {
    // イベント
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); // トークンの所有権移転を示す
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); // 特定トークンについて、誰かに代理移転を許可する
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved); // ownerの全トークンについて、operatorに代理移転を許可/不許可する

    // 関数
    function balanceOf(address owner) external view returns (uint256); // 指定されたアカウントが所有するトークン数を返す
    function ownerOf(uint256 tokenId) external view returns (address owner); // 指定されたtokenIdの所有者を返す
    function safeTransferFrom(address from, address to, uint256 tokenId) external; // fromからtoへ、指定されたtokenIdのトークンを安全に転送する
    function transferFrom(address from, address to, uint256 tokenId) external; // (safeでない) 転送関数
    function approve(address to, uint256 tokenId) external; // 指定されたtokenIdについて、toに代理移転を許可する
    function setApprovalForAll(address operator, bool _approved) external; // 呼び出し元の全トークンについて、operatorに代理移転を許可/不許可する
    function getApproved(uint256 tokenId) external view returns (address operator); // 指定されたtokenIdについて、代理移転を許可されているアドレスを返す
    function isApprovedForAll(address owner, address operator) external view returns (bool); // ownerの全トークンについて、operatorが代理移転を許可されているか返す

    // オプション関数(メタデータ関連)
    // function tokenURI(uint256 tokenId) external view returns (string memory); // トークンのメタデータURIを返す
}

ERC-721の特徴は、各トークンがtokenIdによって一意に識別される点です。残高は単なる数量ではなく、特定のtokenIdのリストとして管理されます。ownerOf(tokenId)関数は、そのトークンの現在の所有者を返すための中核となる機能です。safeTransferFrom関数は、転送先のコントラクトがERC-721トークンを受け取る準備ができているかを確認するチェックを含む、より安全な転送メソッドです。approvesetApprovalForAllは、特定のトークンまたは所有する全てのトークンについて、第三者(例:NFTマーケットプレイスのコントラクト)に販売などの代理操作を許可するための仕組みです。tokenURI関数は、トークンに関する追加情報(画像、属性など)へのリンクを提供するために使用され、これがNFTの多様な表現を可能にしています。

ERC-1155: 複数種類のトークン標準

ERC-1155は、ERC-20とERC-721の両方の性質を併せ持ち、さらに効率化されたマルチトークンの標準規格です。一つのコントラクトで、代替可能なトークン(FT)と代替不可能なトークン(NFT)、あるいはその両方を同時に管理することができます。ゲームのアイテム(消耗品=FT、ユニークアイテム=NFT)などを効率的に扱うために開発されました。

ERC-1155では、各トークンタイプが一意のID(id)を持ち、各IDに対してERC-20のような代替可能な数量を管理することも、ERC-721のような代替不可能な単一のインスタンスとして扱うことも可能です。

interface IERC1155 {
    // イベント
    event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value); // 単一種類のトークン転送/生成/破棄
    event TransferBatch(address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values); // 複数種類のトークン一括転送
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved); // ownerの全トークンタイプについて、operatorに代理移転を許可/不許可する
    event URI(string value, uint256 indexed id); // 特定idのメタデータURIを示す

    // 関数
    function balanceOf(address account, uint256 id) external view returns (uint256); // 指定アカウントが所有する、指定idのトークン数を返す
    function balanceOfBatch(address[] accounts, uint256[] ids) external view returns (uint256[] memory); // 複数のアカウントとidに対して、一括で残高を返す
    function setApprovalForAll(address operator, bool approved) external external; // 呼び出し元の全トークンタイプについて、operatorに代理移転を許可/不許可する
    function isApprovedForAll(address account, address operator) external view returns (bool); // accountの全トークンタイプについて、operatorが代理移転を許可されているか返す
    function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes calldata data) external; // fromからtoへ、指定idのトークンをvalue数、安全に転送する
    function safeBatchTransferFrom(address from, address to, uint256[] ids, uint256[] values, bytes calldata data) external; // fromからtoへ、指定idとvalueのトークンを複数まとめて安全に転送する

    // オプション関数(メタデータ関連)
    // function uri(uint256 id) external view returns (string memory); // 特定idのメタデータURIを返す
}

ERC-1155の大きな特徴は、balanceOfBatchsafeBatchTransferFromのように、複数のトークンタイプや複数の転送を単一のトランザクションで処理できる効率性です。これにより、ガス代の削減にもつながります。idが各トークンタイプを識別し、valueがその数量を示します。ERC-721と同様にsetApprovalForAllによる代理操作の許可機能があります。uri関数は、各トークンタイプ(id)のメタデータを指し示します。ERC-1155は、複雑なトークンエコノミーを持つアプリケーションにおいて、柔軟かつ効率的なトークン管理を実現します。

スマートコントラクトとトークン規格の連携

トークン規格に準拠したスマートコントラクト(以下、トークンコントラクト)を開発する際は、上記のインターフェースを実装します。例えば、ERC-20トークンコントラクトは、ユーザーがtransfer関数を呼び出した際に、内部の残高マッピングを更新するロジックを含みます。

他のスマートコントラクトや外部アプリケーションがトークンを操作する場合、このトークンコントラクトの公開された関数(インターフェースで定義された関数)を呼び出します。例えば、分散型取引所のスマートコントラクトがユーザー間のトークン交換を行う場合、取引所コントラクトは売り手の承認(approve)を得た上で、トークンコントラクトのtransferFrom関数を呼び出して、トークンを買い手のアドレスへ移動させます。

このように、トークン規格は、トークンコントラクトと、それを利用する他のコントラクトやアプリケーションとの間の明確な「契約」(インターフェース)として機能します。これにより、開発者は特定のトークンの内部実装を知らなくても、標準化された方法でトークンを扱うことができるのです。

まとめと次のステップ

ブロックチェーンにおけるトークン規格(ERC-20, ERC-721, ERC-1155など)は、様々な種類のトークンがエコシステム内で円滑に流通し、相互に連携するための基盤となる技術です。共通のインターフェースを定義することで、開発効率、互換性、セキュリティが向上します。

これらの規格を理解することは、ブロックチェーン上のアプリケーション開発、特にdAppsやWeb3サービスの開発を目指す上で非常に重要です。

次のステップとして、実際にこれらのトークン規格に準拠したスマートコントラクトのサンプルコードを読んでみたり、開発環境(例:Hardhat, Truffle)を使って簡単なトークンコントラクトをデプロイしてみたりすることをお勧めします。OpenZeppelinなどのライブラリは、これらの標準規格に準拠した安全なコントラクト実装を提供しており、学習の大きな助けとなるでしょう。また、ERC-4626のような、さらに新しい規格についても調査してみると、ブロックチェーン技術の進化をより深く理解できるはずです。