はじめに

初めまして。 CryptoGamesというブロックチェーンゲーム企業でエンジニアをしている cardene(かるでね) です! スマートコントラクトを書いたり、フロントエンド・バックエンド・インフラと幅広く触れています。

代表的なゲームはクリプトスペルズというブロックチェーンゲームです。

今回は、代替可能トークンであるERC20とマルチトークンであるERC1155を組み合わせて、ERC404やDN404に近い仕組みを提案しているEIP7681についてまとめていきます!

以下にまとめられているものを翻訳・要約・補足しながらまとめていきます。

他にも様々なEIPについてまとめています。

概要

この規格では、ERC20(代替可能トークン)とERC1155(マルチトークン)を統合して、単一のコントラクト内で2つのトークンを管理できる仕組みを提案しています。

ERC20については以下の記事を参考にしてください。

ERC1155については以下の記事を参考にしてください。

動機

ERC20とERC721を統合した規格は、既にERC7631として提案されています。

ERC7631については以下の記事を参考にしてください。

ただ、ERC7631の課題点として、Transferイベントが重複してしまうということがありました。 ERC20にもERC721にもTransferイベントが存在するため、完全な互換性を持つことが難しかったです。

ERC20のTransferイベントは以下です。

js
event Transfer(address indexed from, address indexed to, uint256 value);

ERC721のTransferイベントは以下です。

js
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

ERC1155のTransfer系イベントは以下です。

js
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
);

確かにERC1155だけ異なりますね。

ERC20とERC1155を組み合わせることで、ERC20トークンを取得するとその保有量に比例してERC1155トークンを発行する仕組みを実装でき、NFTの分割所有をネイティブにサポートできるようになります。

ERC404やDN404と呼ばれる規格と同じ仕組みです。 簡単な例で説明すると以下になります。

  • ERC20を10個持っていると、ERC1155を1個mintされる。
  • ERC1155を1個transferされると、ERC20が10個mintされる。
  • ERC1155を1個transferすると、ERC20が10個burnされる。

このように、ERC2010個につきERC11551個などの設定値に基づいて、2つのトークンを管理する仕組みです。

ERC404については以下の記事で詳しく説明しています。

また、ERC20とERC1155の個数同期プロセスにおいて、ERC1155のmintやtransferを除外することもできます。

仕組み

ERC7681に準拠するコントラクトは、ERC20とERC721の両方を実装する必要があります。

ERC7681 Interface

ERC20コントラクトは以下のインターフェースを実装する必要があります。

js
interface IERC7681 /* is IERC20, IERC1155 */ {
    /// The contract MUST contain the following events
    /// ERC20 related events
    event Transfer(address indexed _from, address indexed _to, uint256 _value);
    event Approval(address indexed _owner, address indexed _spender, uint256 _value);

    /// The contract MUST contain the following events
    /// ERC1155 related events
    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);
    event URI(string _value, uint256 indexed _id);

    /// The contract MAY contain the following functions
    /// ERC20 related functions
    function name() public view returns (string);
    function symbol() public view returns (string);
    function decimals() public view returns (uint8);

    /// The contract MUST contain the following functions
    /// ERC20 related functions
    function totalSupply() public view returns (uint256);
    function balanceOf(address _owner) public view returns (uint256);
    function transfer(address _to, uint256 _value) public returns (bool);
    function transferFrom(address _from, address _to, uint256 _value) public returns (bool);
    function approve(address _spender, uint256 _value) public returns (bool);
    function allowance(address _owner, address _spender) public view returns (uint256);

    /// The contract MUST contain the following functions
    /// ERC1155 related functions
    function balanceOf(address _owner, uint256 _id) external view returns (uint256);
    function balanceOfBatch(address[] calldata _owners, uint256[] calldata _ids) external view returns (uint256[] memory);
    function setApprovalForAll(address _operator, bool _approved) external;
    function isApprovedForAll(address _owner, address _operator) external view returns (bool);
    function safeTransferFrom(address _from, address _to, uint256 _id, uint256 _value, bytes calldata _data) external;
    function safeBatchTransferFrom(address _from, address _to, uint256[] calldata _ids, uint256[] calldata _values, bytes calldata _data) external;
}

全てERC20とERC1155に存在する機能たちです。

ERC7681 Option Interface

オプションで実装できるインターフェースで、ERC20とERC1155の同期プロセス中に**ERC1155&&のmintやtransferをスキップする機能を提供しています。

js
interface IERC7681Skippable {
    /// @dev Emitted when the skip ERC1155 token status of `owner` is changed by any mechanism.
    ///
    /// This initial skip ERC1155 token status for `owner` can be dynamically chosen to
    /// be true or false, but any changes to it MUST emit this event.
    event SkipTokenSet(address indexed owner, bool status);

    /// @dev Returns true if ERC-1155 mints and transfers to `owner` SHOULD be
    /// skipped during ERC-20 to ERC-1155 synchronization. Otherwise false.
    /// 
    /// This method MAY revert
    ///
    /// If this method reverts:
    /// - Interacting code SHOULD interpret `setSkipToken` functionality as
    ///   unavailable (and hide any functionality to call `setSkipToken`).
    /// - The skip ERC1155 token status for `owner` SHOULD be interpreted as undefined.
    ///
    /// Once a true or false value has been returned for a given `owner`,
    /// this method MUST NOT revert for the given `owner`.
    function getSkipToken(address owner) external view returns (bool);

    /// @dev Sets the caller's skip ERC1155 token status.
    ///
    /// This method MAY revert
    /// (e.g. insufficient permissions, method not supported).
    ///
    /// Emits a {SkipTokenSet} event.
    function setSkipToken(bool status) external;
}

SkipTokenSet

ERC1155トークンのスキップステータスが変更されたときに発行されるイベントです。

getSkipToken

特定のアドレスがERC1155トークンのmintやtransferをスキップするかどうかを返す関数です。

setSkipToken

bool値で、特定のアドレスがERC1155トークンのmintやtransferをスキップするか設定する関数です。 権限が不足しているとエラーになります。 ここでの権限はアドレスが指定されていないので、単純に自分が保有しているアドレスのみ設定できるということだと思います。

補足

実装の柔軟性

特定の同期ロジックを定めたりせずに、様々な実装に対応できるように作成されています。 ERC20トークンの保有量に基づいてERC1155トークンを同期させたり、1対1で同期させたりできます。 ERC20とERC1155の両方のトークン規格の仕様に完全に準拠している限り、同期方法を自由に決められます。

ERC1155トークンスキップ

ERC20トークンの保有者がコントラkつおの場合、デフォルトのスキップステータスをtrueにすることで、DEXやレンディングプロトコルでの取引においてERC1155トークンの発行を止めることができ、ガス代を削減できます。

互換性

ERC20とERC1155と完全な互換性があります。

セキュリティ

ガス切れによるDos

ERC20トークンをtransferする時、自動的に複数のERC1155トークンのmint、transfer、burnが実行されることがあります。 これは固定のガスコスト( O(1)O(1) )ではなく、アクションの数に比例してガスコストが増加( O(n)O(n) )します。 また、ERC1155のトークンIDの選択によりガスコストが増加する可能性もあります。

ERC1155は、各tokenIdが複数枚存在します。 そのため、ERC721と異なり、どのtokenIdのトークンを発行するかなどを管理する必要があります。

これにより、同期戦略はガスコストの増加を考慮して設計し、ガス切れによるサービス停止などが起きないように注意する必要があります。

引用

Sennett Lau (@sennett-lau), "ERC-7681: Dual Nature Multi Token Protocol [DRAFT]," Ethereum Improvement Proposals, no. 7681, April 2024. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7681.

最後に

今回は「代替可能トークンであるERC20とマルチトークンであるERC1155を組み合わせて、ERC404やDN404に近い仕組みを提案しているEIP7681」についてまとめてきました! いかがだったでしょうか?

質問などがある方は以下のTwitterのDMなどからお気軽に質問してください!

他の媒体でも情報発信しているのでぜひ他も見ていってください!