はじめに

『DApps開発入門』という本や色々記事を書いているかるでねです。

今回は、クロスチェーンでトークンを転送する時にブリッジコントラクトが統一された方法でトークンをmint と burnできるようにする最小限のインターフェースを提案しているERC7802についてまとめていきます!

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

他にも様々なEIP・BIP・SLIP・CAIP・ENSIP・RFC・ACPについてまとめています。

概要

ERC7802とは、クロスチェーン転送時にブリッジコントラクトがトークンをmintおよびburnするための最小限のインターフェースIERC7802を定義する規格です。

この規格では、2つの関数(crosschainMintとcrosschainBurn)と2つのイベント(CrosschainMintとCrosschainBurn)を定義しています。 これにより、オフチェーンの監視ツールがクロスチェーン活動を決定論的にインデックス化できるようになります。

ERC7802はERC20トークンと完全に互換性があり、既存のトークンにも適用可能です。

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

非アップグレード可能なトークンの場合は、ロックボックス(Lockbox)メカニズムを使用して移行できます。

動機

この提案が生まれた背景には以下のような課題がありました。

カノニカルブリッジの現状

すべてのロールアップと複数の重要なサイドチェーンは、ネットワークのコアアーキテクチャの一部としてセキュリティを組み込んだカノニカルブリッジを実装しています。 これらのブリッジはオリジナルトークンに対するmint と burn権限を持っていません。

カノニカルブリッジとは、ロールアップやサイドチェーンが公式に提供する標準ブリッジのことです。 ネットワークのセキュリティモデルに直接組み込まれており、サードパーティのブリッジとは異なり、プロトコルレベルで信頼されています。

そのため、通常はネイティブチェーンで流動性をロック(またはアンロック)し、別のチェーンでラップドトークン(Wrapped Token)をmint(またはburn)するという方式を採用しています。

ラップドトークンとは、元のトークンを1対1で表現するために別のチェーンで発行されるトークンです。 例えば、EthereumのUSDCをOptimismにブリッジすると、Optimism上では「Bridged USDC」としてラップドトークンが発行されます。 元のUSDCとは異なるコントラクトアドレスを持ち、厳密には同一のトークンではありません。

mint と burnが使用される理由は、ネイティブトークンがそのチェーンに存在しないため、新しいトークン表現を作成する必要があるからです。

インターフェースの断片化

各ブリッジが非ネイティブチェーンでのmint と burnに異なるインターフェースを実装しているという問題があります。 このインターフェースの断片化は、チェーン間のクロスチェーン通信において大きな問題となっています。

問題点 影響
関数名の不統一 トークンコントラクトが特定のブリッジに依存
パラメータ形式の違い 後から別のブリッジを追加することが困難
イベント形式の不一致 オフチェーンツールの追跡が複雑化

過去の標準化の試み

過去にもトークンブリッジングインターフェースを標準化する試みがありました。 しかし、サードパーティプロバイダーも独自のクロスチェーントークンフレームワークを開発しています。

各フレームワークはレート制限や手数料スイッチなどの機能を定義し、独自のmint と burnバージョンを実装しています。 その結果、命名規則や構造に一貫性がなく、インターフェースは高度に特化したものになっています。

ERC7802による解決

ERC7802は、ほとんどの標準で使用されている最も関連性が高く最小限のアクションセットを提案しています。 これらのアクションはガバナンスやオーナーの参加を必要としません(例えばレート制限の設定とは異なります)。

解決策 効果
mint と burnの標準化 複数のブリッジと互換性のあるトークン発行が可能
標準化されたイベント インデクサー、分析ツール、監査ツールが一貫した方法で追跡可能
最小限のインターフェース 拡張機能の基盤として機能

仕様

インターフェース定義

IERC7802インターフェースの完全な定義は以下です。

javascript
interface IERC7802 {
    /// @notice クロスチェーンmintが完了した時に発行されるイベント
    /// @param _to トークンを受け取るアドレス
    /// @param _amount mintされるトークン量
    /// @param _sender mint操作を開始したブリッジコントラクトのアドレス
    event CrosschainMint(address indexed _to, uint256 _amount, address indexed _sender);

    /// @notice クロスチェーンburnが完了した時に発行されるイベント
    /// @param _from トークンがburnされるアドレス
    /// @param _amount burnされるトークン量
    /// @param _sender burn操作を開始したブリッジコントラクトのアドレス
    event CrosschainBurn(address indexed _from, uint256 _amount, address indexed _sender);

    /// @notice クロスチェーン転送でトークンをmintするためにブリッジが呼び出す関数
    /// @param _account トークンを受け取るアドレス
    /// @param _amount mintするトークン量
    function crosschainMint(address _account, uint256 _amount) external;

    /// @notice クロスチェーン転送でトークンをburnするためにブリッジが呼び出す関数
    /// @param _account トークンがburnされるアドレス
    /// @param _amount burnするトークン量
    function crosschainBurn(address _account, uint256 _amount) external;
}

このインターフェースは、クロスチェーン転送に必要な最小限の機能のみを定義しています。 ブリッジ固有のロジックはブリッジコントラクト側に実装され、トークンコントラクトはシンプルに保たれます。

インターフェースID

ERC165に準拠したインターフェースIDは0x33331994です。 このIDは、2つの関数セレクタのXOR演算によって計算されます。

text
crosschainMint(address,uint256) XOR crosschainBurn(address,uint256) = 0x33331994

トークンコントラクトはsupportsInterface関数でこのIDを返すことで、ERC7802への対応を示すことができます。

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

関数

crosschainMint
javascript
function crosschainMint(address _account, uint256 _amount) external;

ブリッジコントラクトがクロスチェーン転送時にトークンをmintするためのエントリーポイントです。

この関数が呼び出されると、指定されたアドレスに指定された量のトークンがmintされます。 実装では、標準的なERC20のTransferイベントをaddress(0)から発行する必要があります。 また、CrosschainMintイベントも発行する必要があります。

パラメータ 型 説明
_account address トークンを受け取るアドレス
_amount uint256 mintするトークン量

crosschainBurn
javascript
function crosschainBurn(address _account, uint256 _amount) external;

ブリッジコントラクトがクロスチェーン転送時にトークンをburnするためのエントリーポイントです。

この関数が呼び出されると、指定されたアドレスから指定された量のトークンがburnされます。 ERC5679に従い、Transferイベントをaddress(0)へ発行することが推奨されます。 また、CrosschainBurnイベントも発行する必要があります。

パラメータ 型 説明
_account address トークンがburnされるアドレス
_amount uint256 burnするトークン量

イベント

CrosschainMint
javascript
event CrosschainMint(address indexed _to, uint256 _amount, address indexed _sender);

クロスチェーンmint操作が成功した時に発行されるイベントです。

このイベントにより、オフチェーンのインデクサーや分析ツールがクロスチェーンでのmint操作を追跡できます。 _senderパラメータにより、どのブリッジがmint操作を実行したかを特定できます。

パラメータ 型 indexed 説明
_to address yes トークンを受け取るアドレス
_amount uint256 no mintされたトークン量
_sender address yes mint操作を実行したブリッジコントラクト

CrosschainBurn
javascript
event CrosschainBurn(address indexed _from, uint256 _amount, address indexed _sender);

クロスチェーンburn操作が成功した時に発行されるイベントです。

このイベントにより、オフチェーンのインデクサーや分析ツールがクロスチェーンでのburn操作を追跡できます。 _senderパラメータにより、どのブリッジがburn操作を実行したかを特定できます。

パラメータ 型 indexed 説明
_from address yes トークンがburnされたアドレス
_amount uint256 no burnされたトークン量
_sender address yes burn操作を実行したブリッジコントラクト

補足

設計哲学

ERC7802の設計における核心的な決定事項は「ブリッジ非依存性」と「拡張性」です。

ブリッジ非依存性

このインターフェースは、トークンではなくブリッジがクロスチェーンアクションを処理するロジックを含むように設計されています。 この関心の分離を維持することで、トークンコントラクトはシンプルに保たれ、攻撃対象面(Attack Surface)が削減され、監査やアップグレードが容易になります。

提案されたインターフェースを実装することで、トークンはさまざまなブリッジ設計でサポートできるようになります。

ブリッジタイプ 動作
Lock/Unlockブリッジ 従来通り動作可能、トークン変更不要
burn と mintブリッジ 汎用的で最小限のインターフェースを使用可能、ブリッジ固有の表現が不要
拡張性

この最小限のインターフェースは、他の標準を構築するための基盤レイヤーとして機能します。 トークン発行者やブリッジコントラクトは、コアインターフェースを変更することなく、mint と burn制限、クロスチェーン転送手数料などの機能を追加できます。

このインターフェースは意図的に中立であり、以下の条件を課していません。

項目 説明
アクセス制御 crosschainMintとcrosschainBurnを呼び出す権限者はトークン発行者が決定
ゼロ額の呼び出し ゼロ額での呼び出しを許可するかリバートするかはトークン発行者が決定

ローカルとクロスチェーンのmint と burnの分離

異なるアクション

ローカルのmint と burnとクロスチェーンのmint と burnは根本的に異なります。

種類 特徴
ローカルmint と burn トークンの作成または破棄により総供給量が変化
クロスチェーンmint と burn 全チェーンの総流通量は一定を維持(チェーン間で転送されるため)

クロスチェーン転送でトークンをmint と burnするエージェントは、トークンオーナーとは根本的に異なります。 したがって、2つのアクターが異なる権限を持つことは理にかなっています。 クロスチェーンアクションには異なるチェック、アクセス制御、ロジック(mint と burn制限など)を持たせることが合理的です。

関心の分離

ローカルとクロスチェーンのmint と burnを同じ関数に統合すると、異なる運用ロジックが絡み合った複雑な実装になる可能性があります。 2つに分割することで、関心が分離され、コードベースがクリーンで保守しやすくなります。

この関心の分離は以下の点で特に重要です。

観点 効果
アップグレード アクセス制御、制限、ロジックの変更は、標準のローカルmint と burn実装を変更せずに、分離されたクロスチェーン関数のみに影響
異なるチェーンとの統合 ERC20をクロスチェーン互換にするには、各チェーンに対応するアクセス制御でERC7802拡張を実装するだけでよい

例えば、Optimismと統合する場合、ERC20はOptimismブリッジにアクセス権を付与します。 Arbitrumと統合する場合、Arbitrumブリッジにアクセス権を付与します。 ローカルのmint と burn関数は変更されません。 クロスチェーン操作に専用の関数を使用することで、各チェーンのベース実装を変更する必要がなく、よりモジュラーなアプローチが可能になります。

専用イベント

クロスチェーン専用のイベントを持つことにも同様の理由があります。 この分離により、インデクサー、分析ツール、監査者の作業が大幅に容易になります。 クロスチェーンアクティビティの直接的な追跡、異常の検出、ブリッジ操作の監視が可能になります。

クロスチェーンイベントとローカルイベントが区別できない場合、オフチェーンエージェントはそれらを区別するための複雑なロジックを実装する必要があり、エラーや非効率性の可能性が高まります。

ERC-165インターフェース

ERC165の組み込みは、インテグレーターに追加のセキュリティチェックを提供します。 supportsInterfaceメソッドでインターフェース識別子を提供することで、呼び出し元はトークンがIERC7802インターフェースに準拠していることをプログラム的に確認できます。

この検証により、トークンがcrosschainMintとcrosschainBurnの両方の関数をサポートしていることが保証されます。 一方の関数のみが実装されているような不完全な実装を防ぎます。 そのような不完全な実装は、ユーザーがトークンをburnしてブリッジアウトしたが、戻ってきたときにmintできないといった問題につながり、クロスチェーンアクションの失敗を引き起こす可能性があります。

このチェックはトークンコントラクトが存在するチェーン上でのみローカルに実行できることに注意してください。 受信側チェーンのトークンもIERC7802インターフェースをサポートしているという固有の保証はありません。 インターフェースサポートのクロスチェーン一貫性を確保することは、ブリッジ実装の責任です。

クロスチェーン転送フロー

クロスチェーン転送の典型的なフローは以下です。

sequenceDiagram
    participant User as ユーザー
    participant TokenA as トークン(チェーンA)
    participant BridgeA as ブリッジ(チェーンA)
    participant BridgeB as ブリッジ(チェーンB)
    participant TokenB as トークン(チェーンB)

    User->>BridgeA: 転送リクエスト
    BridgeA->>TokenA: crosschainBurn(user, amount)
    TokenA-->>BridgeA: CrosschainBurnイベント発行
    BridgeA->>BridgeB: クロスチェーンメッセージ
    BridgeB->>TokenB: crosschainMint(user, amount)
    TokenB-->>BridgeB: CrosschainMintイベント発行
    TokenB-->>User: トークン受け取り

このフローでは、ユーザーがチェーンAでブリッジにトークン転送をリクエストすると、ブリッジがトークンコントラクトのcrosschainBurnを呼び出します。 burn完了後、ブリッジはクロスチェーンメッセージをチェーンBに送信し、チェーンB側のブリッジがcrosschainMintを呼び出してトークンを発行します。

後方互換性

ERC7802はERC20と完全に互換性があります。 この規格は既存のERC20機能を拡張するものであり、既存のトークンの動作を変更しません。

動機セクションで説明したように、最小限で柔軟なクロスチェーン標準インターフェースが必要です。 標準化されたフォーマットなしでより多くのトークンがデプロイされるにつれて、問題は大きくなります。

トークンタイプ別の対応

トークンタイプ 対応方法
アップグレード可能なトークン 新しいインターフェースを実装するようにアップグレード可能
非アップグレード可能なトークン トークン自体にインターフェースを実装できない

非アップグレード可能なトークンの移行

非アップグレード可能なトークンの場合、xERC-20で提案されているロックボックスメカニズムを使用して標準準拠バージョンに移行できます。

ロックボックスの仕組みは以下の通りです。

  1. mint不可能なトークンをロックする
  2. 同量のインターフェース準拠トークンをmintする
  3. ブリッジコントラクトがネイティブチェーンでロックボックスとして機能できる

この方法により、既存のトークンを変更することなく、クロスチェーン機能を追加できます。

ブリッジコントラクトの更新

ブリッジコントラクトもインターフェースと統合するためにアップグレードが必要になります。

セキュリティ

セキュリティ考慮事項

ERC7802を実装する時は、以下のセキュリティ考慮事項に注意してください。

アクセス制御(パーミッション)

トークン発行者は、crosschainMintとcrosschainBurn関数を呼び出す権限のあるコントラクトを制御する責任があります。 バグのある、または悪意のある認可された呼び出し元は、トークンを不適切にmintまたはburnし、トークン保有者に損害を与え、統合を妨害する可能性があります。

リスク 影響
悪意のある呼び出し元の認可 無制限のトークン発行が可能
バグのあるコントラクトの認可 ユーザー資産の不正なburn
損失の最小化

潜在的な損失を最小限に抑える1つの方法は、xERC-20で提案されているようなmint と burn制限を導入することです。 これらの機能は提案されたインターフェースと完全に互換性があります。

緩和策 効果
mint と burn制限 一定期間内のmint と burn量を制限し、被害を抑制
レート制限 異常な大量操作を検出・防止
ラップドネイティブトークン

この規格は、WETHのようなラップドネイティブトークンには使用すべきではありません。 ブリッジが原資産を制御しない場合、担保なしのmintにつながる可能性があります。

唯一の安全な例外は、ブリッジが両チェーンでネイティブトークンを対称的にburn と mintでき、適切な担保化を確保できる場合です。 例えば、チェーンBでcrosschainMintによりWETHが発行される場合、チェーンAで対応するETHがロックされている必要があります。

参考実装

ERC7802の参考実装は以下です。

IERC7802インターフェース

まず、IERC7802インターフェースの定義です。

javascript
// SPDX-License-Identifier: CC0-1.0
pragma solidity 0.8.25;

import "@openzeppelin/contracts/utils/introspection/IERC165.sol";

/// @title IERC7802
/// @notice クロスチェーンERC20転送のためのインターフェースを定義
interface IERC7802 is IERC165 {
    /// @notice クロスチェーン転送でトークンがmintされた時に発行
    /// @param to トークンがmintされるアカウントのアドレス
    /// @param amount mintされるトークン量
    /// @param sender crosschainMintを呼び出した呼び出し元(msg.sender)のアドレス
    event CrosschainMint(address indexed to, uint256 amount, address indexed sender);

    /// @notice クロスチェーン転送でトークンがburnされた時に発行
    /// @param from トークンがburnされるアカウントのアドレス
    /// @param amount burnされるトークン量
    /// @param sender crosschainBurnを呼び出した呼び出し元(msg.sender)のアドレス
    event CrosschainBurn(address indexed from, uint256 amount, address indexed sender);

    /// @notice クロスチェーン転送でトークンをmint
    /// @param _to トークンをmintするアドレス
    /// @param _amount mintするトークン量
    function crosschainMint(address _to, uint256 _amount) external;

    /// @notice クロスチェーン転送でトークンをburn
    /// @param _from トークンをburnするアドレス
    /// @param _amount burnするトークン量
    function crosschainBurn(address _from, uint256 _amount) external;
}

このインターフェースはIERC165を継承しており、supportsInterfaceによる検出が可能です。

CrosschainERC20実装

インターフェースを実装したトークンコントラクトの例です。

javascript
// SPDX-License-Identifier: CC0-1.0
pragma solidity 0.8.25;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract CrosschainERC20 is ERC20, IERC7802 {
    /// @notice トークンのmint/burnが許可されたTOKEN_BRIDGEコントラクトのアドレス
    address public immutable TOKEN_BRIDGE;

    /// @notice 認可されていないアクセスに対するカスタムエラー
    error Unauthorized();

    /// @notice TOKEN_BRIDGEアドレスを設定するコンストラクタ
    /// @param _tokenBridge TOKEN_BRIDGEのアドレス
    constructor(address _tokenBridge, string memory name, string memory symbol) ERC20(name, symbol) {
        require(_tokenBridge != address(0), "Invalid TOKEN_BRIDGE address");
        TOKEN_BRIDGE = _tokenBridge;
    }

    /// @notice TOKEN_BRIDGEのみが呼び出せるようにする修飾子
    modifier onlyTokenBridge() {
        if (msg.sender != TOKEN_BRIDGE) revert Unauthorized();
        _;
    }

    /// @notice TOKEN_BRIDGEがトークンをmintできるようにする
    /// @param _to トークンをmintするアドレス
    /// @param _amount mintするトークン量
    function crosschainMint(address _to, uint256 _amount) external onlyTokenBridge {
        _mint(_to, _amount);
        emit CrosschainMint(_to, _amount, msg.sender);
    }

    /// @notice TOKEN_BRIDGEがトークンをburnできるようにする
    /// @param _from トークンをburnするアドレス
    /// @param _amount burnするトークン量
    function crosschainBurn(address _from, uint256 _amount) external onlyTokenBridge {
        _burn(_from, _amount);
        emit CrosschainBurn(_from, _amount, msg.sender);
    }

    function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {
        return interfaceId == type(IERC7802).interfaceId || interfaceId == type(IERC165).interfaceId;
    }
}

この実装のポイントは以下の通りです。

ポイント 説明
TOKEN_BRIDGEのimmutable化 デプロイ後の変更を防ぎ、セキュリティを強化
onlyTokenBridge修飾子 認可されたブリッジのみがmint と burn可能
カスタムエラーUnauthorized ガス効率の良いエラーハンドリング
コンストラクタでのゼロアドレスチェック 不正なブリッジアドレスの設定を防止

_mintと_burnはOpenZeppelinのERC20から継承した内部関数を使用しており、標準的なTransferイベントも発行されます。 supportsInterface関数はERC165に準拠し、ERC7802のインターフェースIDを返します。

引用

最後に

今回は「ERC7802によるクロスチェーントークンインターフェースの標準化」についてまとめてきました! いかがだったでしょうか?

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

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