はじめに:トークン標準とは? 🤔
Ethereumブロックチェーン上でスマートコントラクトを使って様々な「トークン」を作成できます。トークンは、仮想通貨、ポイント、会員権、ゲーム内アイテム、デジタルアートなど、様々な価値を表現するために使われます。
しかし、開発者がそれぞれ独自のルールでトークンを作ってしまうと、ウォレットや取引所などのサービスが個々のトークンに対応するのが大変になります。そこで重要になるのがトークン標準です。トークン標準は、トークンが持つべき機能やインターフェース(関数の名前や引数など)を定めた共通のルールセットです。これにより、標準に準拠したトークンは互換性を持ち、様々なアプリケーションで簡単に扱えるようになります。
このステップでは、Ethereumで最も広く使われている3つのトークン標準、ERC-20、ERC-721、ERC-1155について学び、それぞれの特徴と簡単な実装方法を見ていきましょう!🚀
ERC-20: 代替可能なトークン (Fungible Tokens) 💰
ERC-20は、代替可能 (Fungible) なトークンのための標準規格です。代替可能とは、どのトークンも同じ価値を持ち、互いに交換可能であることを意味します。例えば、日本円の100円玉は、誰が持っているものでも同じ価値があり、区別なく交換できますよね。ERC-20トークンもこれと同じ性質を持ちます。
仮想通貨(例:USDT, DAI)、ガバナンストークン、ユーティリティトークンなど、多くのプロジェクトで利用されています。
主な機能
ERC-20で定義されている主な関数とイベントは以下の通りです。
name()
: トークンの名前(例: “MyToken”)を返す。symbol()
: トークンのシンボル(例: “MTK”)を返す。decimals()
: トークンの小数点以下の桁数を返す(通常は18)。totalSupply()
: トークンの総供給量を返す。balanceOf(address account)
: 指定されたアカウントのトークン残高を返す。transfer(address recipient, uint256 amount)
: 指定されたアドレスにトークンを送金する。allowance(address owner, address spender)
: `owner`が`spender`に送金を許可した残りのトークン量を返す。approve(address spender, uint256 amount)
: `spender`が自分の代わりに`amount`までのトークンを送金することを許可する。transferFrom(address sender, address recipient, uint256 amount)
: `sender`から`recipient`へトークンを送金する(`approve`で許可されている必要がある)。event Transfer(address indexed from, address indexed to, uint256 value)
: トークンが送金されたときに発行されるイベント。event Approval(address indexed owner, address indexed spender, uint256 value)
: `approve`が成功したときに発行されるイベント。
簡単な実装例(インターフェース)
ERC-20のインターフェースは以下のようになります。実際にトークンを作成する際は、これらの関数とイベントを実装します。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
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 recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
// Optional functions
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
}
実際にERC-20トークンを実装する際は、ゼロから書くのではなく、OpenZeppelin Contractsのような信頼性の高いライブラリを利用するのが一般的です。これにより、安全で標準に準拠したトークンを簡単に作成できます。
ERC-721: 代替不可能なトークン (Non-Fungible Tokens – NFTs) 🖼️
ERC-721は、代替不可能 (Non-Fungible) なトークン、いわゆるNFTのための標準規格です。代替不可能とは、各トークンがユニークであり、他のトークンと区別されることを意味します。例えば、一点物のアート作品や、シリアルナンバー付きの限定グッズなどがこれにあたります。
NFTは、デジタルアート、コレクターズアイテム、ゲーム内アイテム(武器、キャラクターなど)、不動産所有権、会員権など、ユニークな価値を持つものをブロックチェーン上で表現するために広く使われています。
主な機能
ERC-721で定義されている主な関数とイベントは以下の通りです。
balanceOf(address owner)
: 指定されたアドレスが所有するNFTの数を返す。ownerOf(uint256 tokenId)
: 指定された`tokenId`のNFTを所有するアドレスを返す。transferFrom(address from, address to, uint256 tokenId)
: `from`から`to`へ指定された`tokenId`のNFTを転送する。safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data)
: `transferFrom`に加えて、転送先がNFTを受け取れるコントラクトかどうかのチェックを行う安全な転送。approve(address to, uint256 tokenId)
: 特定の`tokenId`のNFTの操作(転送など)を`to`アドレスに許可する。getApproved(uint256 tokenId)
: 特定の`tokenId`のNFTに対して操作許可を得ているアドレスを返す。setApprovalForAll(address operator, bool approved)
: 自分の所有する全てのNFTに対する操作権限を`operator`アドレスに与える(または剥奪する)。isApprovedForAll(address owner, address operator)
: `operator`が`owner`の全てのNFTに対する操作権限を持っているかどうかを返す。event Transfer(address indexed from, address indexed to, uint256 indexed tokenId)
: NFTが転送されたときに発行されるイベント。event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId)
: `approve`が成功したときに発行されるイベント。event ApprovalForAll(address indexed owner, address indexed operator, bool approved)
: `setApprovalForAll`が成功したときに発行されるイベント。
簡単な実装例(インターフェース)
ERC-721のコアインターフェースは以下のようになります。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
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);
function balanceOf(address owner) external view returns (uint256 balance);
function ownerOf(uint256 tokenId) external view returns (address owner);
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
function safeTransferFrom(address from, address to, uint256 tokenId) external;
function transferFrom(address from, address to, uint256 tokenId) external;
function approve(address to, uint256 tokenId) external;
function setApprovalForAll(address operator, bool _approved) external;
function getApproved(uint256 tokenId) external view returns (address operator);
function isApprovedForAll(address owner, address operator) external view returns (bool);
// Optional: Metadata Extension
// function name() external view returns (string memory);
// function symbol() external view returns (string memory);
// function tokenURI(uint256 tokenId) external view returns (string memory);
// Optional: Enumerable Extension
// function totalSupply() external view returns (uint256);
// function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId);
// function tokenByIndex(uint256 index) external view returns (uint256);
}
ERC-721も、OpenZeppelin Contractsなどのライブラリを使って実装することが推奨されます。メタデータ(名前、説明、画像など)を扱うための拡張機能なども用意されています。
ERC-1155: マルチトークン標準 🎮
ERC-1155は、複数のトークンタイプを単一のコントラクトで管理できる、より効率的なトークン標準です。ERC-20のような代替可能なトークンと、ERC-721のような代替不可能なトークン(NFT)の両方を、同じコントラクト内で扱うことができます。さらに、「半代替可能 (Semi-Fungible)」なトークン(例:ゲーム内で使用すると消費されるアイテム)も表現できます。
ERC-1155の大きな利点は、バッチ処理が可能であることです。複数のトークン(異なる種類でも可)を一度のトランザクションで転送できるため、ガス代を大幅に節約できます。これは特に、多数のアイテムが存在するブロックチェーンゲームなどで非常に有効です。
主な特徴と機能
- 単一コントラクト、複数トークン: 1つのコントラクトで、異なるIDを持つ複数のトークン(代替可能、代替不可能)を管理します。
- バッチ転送: 複数のトークンIDと数量を一度に転送できます (
safeBatchTransferFrom
)。 - バッチ残高確認: 複数のアカウントとトークンIDの組み合わせについて、一度に残高を確認できます (
balanceOfBatch
)。 - バッチ承認: ERC-721と同様の
setApprovalForAll
によるオペレーターへの一括承認が可能です。(個別トークンIDごとの`approve`はありません) - IDごとの残高: 残高確認 (
balanceOf
) は、アカウントアドレスとトークンIDの両方を指定します。 - 安全な転送規則: ERC-721と同様に、トークンを受け取れないコントラクトへの誤送信を防ぐための
onERC1155Received
フックがあります。 - 主な関数:
balanceOf
,balanceOfBatch
,safeTransferFrom
,safeBatchTransferFrom
,setApprovalForAll
,isApprovedForAll
- 主なイベント:
TransferSingle
,TransferBatch
,ApprovalForAll
,URI
簡単な実装例(インターフェース)
ERC-1155のコアインターフェースの主要部分は以下のようになります。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
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 account, address indexed operator, bool approved);
event URI(string value, uint256 indexed id);
function balanceOf(address account, uint256 id) external view returns (uint256);
function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) external view returns (uint256[] memory);
function setApprovalForAll(address operator, bool approved) external;
function isApprovedForAll(address account, address operator) external view returns (bool);
function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external;
function safeBatchTransferFrom(address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data) external;
// Optional: Metadata Extension
// function uri(uint256 id) external view returns (string memory);
}
ERC-1155の実装も、OpenZeppelin Contractsを利用することで、安全かつ効率的に行うことができます。
各標準の比較まとめ 📊
ERC-20、ERC-721、ERC-1155の主な違いをまとめます。
特徴 | ERC-20 | ERC-721 | ERC-1155 |
---|---|---|---|
トークンの性質 | 代替可能 (Fungible) | 代替不可能 (Non-Fungible) | 代替可能 & 代替不可能 (Multi-Token) |
主な用途 | 仮想通貨, ポイント, 投票権 | NFTアート, コレクティブル, ゲームアイテム(ユニーク) | ゲーム(複数アイテム), バンドル販売, 効率的な複数トークン管理 |
キーコンセプト | 数量 (Amount) | トークンID (Token ID) | トークンID (Token ID) & 数量 (Amount) |
単位 | 数量で管理 | 個別のトークンとして管理 | IDごとに数量で管理 |
バッチ転送 | ❌ 不可 | ❌ 不可 (一部拡張で可能) | ✅ 可能 |
ガス効率 (複数種類転送時) | 低い (個別トランザクション) | 低い (個別トランザクション) | 高い (バッチ処理) |
管理コントラクト数 | 1トークン種別 = 1コントラクト | 1コレクション = 1コントラクト | 複数トークン種別 = 1コントラクト |
実装上の注意点と推奨事項 💡
- OpenZeppelinの利用: これらのトークン標準を実装する際は、セキュリティ監査済みで広く使われているOpenZeppelin Contractsライブラリの使用を強く推奨します。これにより、一般的な脆弱性を避け、開発時間を短縮できます。
- ガス効率: 特にNFT (ERC-721) や、大量のトークンを扱う場合、ガス代は重要な考慮事項です。ERC-1155はバッチ処理によりガス効率が良い場合がありますが、コントラクトの複雑性は増します。ERC-721でも、Enumerable拡張などはガス代が高くなる傾向があるため、必要性を検討しましょう。
- セキュリティ: トークンコントラクトは資産を扱うため、セキュリティは最優先事項です。OpenZeppelinなどのライブラリを使用することに加え、アクセス制御(誰がミントできるか、など)や、オーバーフロー/アンダーフロー対策(Solidity 0.8以降は標準でチェックされます)などを適切に実装することが重要です。
- メタデータ管理: 特にNFT (ERC-721, ERC-1155) では、トークンに関連付けられるメタデータ(名前、説明、画像URLなど)の管理方法が重要です。オンチェーンに保存するか、IPFSなどのオフチェーンストレージを利用するかなどを検討します。
tokenURI
(ERC-721) やuri
(ERC-1155) 関数でメタデータへのリンクを提供します。
まとめ 🎉
今回は、Ethereumエコシステムにおける主要なトークン標準であるERC-20、ERC-721、ERC-1155について学びました。
- ERC-20 は、通貨のような代替可能なトークンの標準です。
- ERC-721 は、アートやコレクティブルのようなユニークな価値を持つ代替不可能なトークン (NFT) の標準です。
- ERC-1155 は、代替可能・不可能の両方を単一コントラクトで効率的に扱えるマルチトークン標準で、特にゲームなどで有用です。
これらの標準を理解し、適切に使い分けることで、様々なユースケースに対応した信頼性の高いトークンを作成することができます。OpenZeppelinなどのライブラリを活用し、実際にこれらのトークンコントラクトを作成・デプロイしてみることをお勧めします。次のステップでは、これらの知識を活かして、より実践的な開発に挑戦していきましょう!💪
- OpenZeppelin Contracts Documentation: https://docs.openzeppelin.com/contracts/5.x/
- Ethereum.org Token Standards: https://ethereum.org/ja/developers/docs/standards/tokens/
コメント