はじめに

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

今回は、レンディングによってトークン供給を増やしつつ、準備金の割合から安全性や償還可能性を判断できる仕組みを提案しているERC7770についてまとめていきます!

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

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

概要

ERC7770は、「部分的にしか裏付け資産と交換できないが、他の担保資産によって全体としては完全に裏付けられている合成資産(シンセティックアセット)」のための新しいトークン規格です。

ここでいう合成資産とは、元となる資産(例:DAIやETH)そのものではなく、それを基に発行された別チェーン上の表現や、担保によって発行される疑似的な資産を指します。 通常のブリッジ資産のように「常に1:1で即座に引き出せる」わけではなく、流動性の状況によっては一時的に償還できない場合があります。

ERC7770は以下の2つを標準化します。

  • 部分準備型(フラクショナルリザーブ)で発行されるトークンのミント(発行)インターフェース。
  • トークン保有者や貸し手が、そのトークンに内在する経済的リスク(準備率、担保状況、償還可能性など)を把握できるようにするための情報公開インターフェース。

つまりERC7770は、「常に全額が即時償還可能ではない合成トークンを、安全に発行・運用し、そのリスク状態を標準化された方法で可視化するための規格」です。

動機

L1・L2の増加とブリッジ資産の本質

近年、EthereumのL2や新しいL1が急増しました。この状況はしばしば「カンブリア爆発(多様な生態系が一気に生まれる現象)」に例えられます。

その結果、多数のブリッジ資産が登場しました。 例えば以下です。

例 説明
Arbitrum上のETH EthereumメインネットのETHをロックして発行される合成表現
BSC上のWETH Ethereum上のWETHを担保に発行される合成表現

これらは「合成資産」であり、技術的には元のETHと完全に同一ではありません。 ただし、ブリッジでは通常、以下の性質を持ちます。

  • 元資産が100%ロックされている。
  • 時間はかかるが、必ず1:1で償還できる。

つまり「完全準備型」の合成資産です。

部分準備型トークンという発想

ERC7770が対象とするのは、これとは異なる「部分準備型(フラクショナルリザーブ)」の合成資産です。

部分準備型では、トークンの総発行量すべてが、常に同量の元資産で直接裏付けられているわけではありません。 代わりに以下の仕組みを取ります。

  • 一部は元資産そのもの(例:DAI)で裏付け。
  • それ以外は、別の担保資産(ETHなど)を預け入れて借入によって発行。

これにより、チェーンやエコシステム内の通貨供給量を拡張できます。

frDAIの例での説明

例として、部分準備型のDAI合成トークンである「frDAI」を考えます。

frDAIは以下の方法で発行されます。

  1. ユーザーが1 DAIを預けると、1 frDAIが発行されます。
  2. ユーザーが1 DAI相当以上の担保(例:ETH)を預けると、1 frDAIを借りて発行できます。

償還の仕組みは以下です。

  • コントラクト内にDAI残高がある限り、frDAIは即座に1:1でDAIに交換できます。
  • すべてのDAI準備金が引き出された場合、残りのfrDAIは借り手の返済を待つ必要があります。
  • その間、市場ではfrDAIの価格が一時的に1 DAIを下回る可能性があります。

これは銀行の取り付け騒ぎと似た状況で、流動性不足による一時的な乖離が起こり得ます。

複数のリスク管理主体と標準化の必要性

部分準備型トークンは、以下のような複雑な構造を持つことが想定されています。

  • 複数のレンディングプロトコルがミント権限を持つ。
  • 複数のリスク管理者(担保率、清算条件などを決める主体)が存在する。
  • 担保構成や準備率が時間とともに変化する。

このとき、トークン保有者や貸し手が知りたい情報は以下です。

知りたい情報 意味
準備率 どれくらいが即時償還可能か
担保構成 何で裏付けられているか
債務状況 借り手がどれだけ発行しているか
流動性リスク 取り付け時に償還できるか

これらをプロトコルごとにバラバラの方法で公開すると、比較も監査も困難になります。

ERC7770の立ち位置

ERC7770は、部分準備銀行モデルそのものの健全性(倒産しないか、取り付けに耐えられるか)を規定するものではありません。

目的は以下です。

  • 部分準備型で発行される合成トークンのミント方法を共通化する。
  • 準備率や担保状況などの「経済的リスク情報」を、トークン標準として取得可能にする。
  • 保有者やレンダーが、リスクを定量的に把握できる基盤を提供する。

つまりERC7770は、「フラクショナルリザーブ型の合成資産を、安全に評価できる共通インターフェースを提供する標準」です。

仕様

インターフェース

ERC7770は、以下のようなインターフェースを定義します。IERC20を継承しており、通常のトークン操作に加えて、部分準備に特化したイベントと関数を持ちます。

IERCXXX.sol
interface IERCXXX is IERC20 {
  // events
  event MintFractionalReserve(address indexed minter, address to, uint256 amount);
  event BurnFractionalReserve(address indexed burner, address from, uint256 amount);
  event SetSegregatedAccount(address account, bool segregated);

  // functions
  // setters
  function fractionalReserveMint(address _to, uint256 _amount) external;
  function fractionalReserveBurn(address _from, uint256 _amount) external;
 
 // getters
  function totalBorrowedSupply() external view returns (uint256);
  function requiredReserveRatio() external view returns (uint256);
  function segregatedAccount(address _account) external view returns (bool);
  function totalSegregatedSupply() external view returns (uint256);
}

それぞれの役割を整理すると以下です。

要素 意味
MintFractionalReserve 借入によるミントが発生したことを通知するイベント
BurnFractionalReserve 借入返済によりBurnされたことを通知するイベント
SetSegregatedAccount 分離管理口座(後述)の設定変更を通知するイベント
fractionalReserveMint 担保を元に借入としてトークンを発行する関数
fractionalReserveBurn 借入返済によりトークンをBurnする関数
totalBorrowedSupply 借入によって発行され、まだ返済されていない総量
requiredReserveRatio 最低限維持すべき準備率
segregatedAccount 特定アドレスが分離管理対象かどうか
totalSegregatedSupply 分離管理口座に存在するトークン総量

準備率

準備率とは、「即時に償還可能な現金相当トークン」が、全体供給量の中でどれくらいの割合を占めているかを表す指標です。

即時償還可能とは、「借入によってミントされたものではないトークン」であり、さらに「分離管理口座(Segregated Account)に置かれている分」は流動性として使えないため除外されます。

定義は以下です。

totalSupply()−totalBorrowedSupply()−∑a∈SegregatedbalanceOf(a)totalSupply()\frac{totalSupply() - totalBorrowedSupply() - \sum_{a \in Segregated} balanceOf(a)}{totalSupply()}

この値に 1e18 を掛けたものが、requiredReserveRatio() 以上でなければなりません。 これを下回る状態では、新たな部分準備ミントは実行できず、コントラクトは必ず revert します。

これは「最低限この割合の即時償還資金を常に保持していなさい」という安全装置です。

ミントおよびBurn機能

fractionalReserveMint と fractionalReserveBurn は、誰でも呼べる関数ではなく、リスク管理者やレンディングプロトコルなど、権限を持つアドレスからのみ呼ばれることが想定されています。

ミント処理

fractionalReserveMint(_to, _amount) が成功すると、以下が必ず同時に起こります。

変化する値 増加量
totalSupply +_amount
totalBorrowedSupply +_amount
_to の残高 +_amount

同時に MintFractionalReserve イベントが発行されます。

ただし、ミント後の準備率が requiredReserveRatio() を下回る場合、この処理は必ず revert しなければなりません。

仕様中では別の形の準備率定義も示されており、以下です。

totalSupply()−∑a∈SegregatedbalanceOf(a)totalSupply()+totalBorrowedSupply()\frac{totalSupply() - \sum_{a \in Segregated} balanceOf(a)}{totalSupply() + totalBorrowedSupply()}

こちらも同様に、requiredReserveRatio() を超えてしまう場合、ミントは許可されません。 実装では、ミント前後の状態で条件を満たすかを厳密にチェックする必要があります。

Burn処理

fractionalReserveBurn(_from, _amount) が成功すると、以下が同時に減少します。

変化する値 減少量
totalSupply -_amount
totalBorrowedSupply -_amount
_from の残高 -_amount

このとき BurnFractionalReserve イベントが必ず発行されます。 これは借入の返済に相当します。

分離管理口座(Segregated Accounts)

分離管理口座とは、流動性としてカウントしてはいけない特別なアドレス群です。 例えば、担保清算プール、保険基金、利息分配待機口座などが該当します。

仕様では常に以下が成り立たなければなりません。

∑a∈SegregatedbalanceOf(a)=totalSegregatedSupply()\sum_{a \in Segregated} balanceOf(a) = totalSegregatedSupply()

つまり、分離管理対象とマークされたすべてのアドレスの残高合計は、totalSegregatedSupply() と完全に一致していなければならず、帳尻が合わない実装は規格違反になります。

アカウント残高と利息分配

fractionalReserveMint は、基本的にレンディングとセットで使われることが想定されています。 ユーザーは担保を預け、トークンを借り、その対価として利息を支払います。

この利息収入の一部は、以下の条件を満たす保有者に分配されることが想定されています。

  • 分離管理口座ではないアドレス
  • つまり、純粋な流動性提供者・保有者

ただし、ERC7770は利息の計算方法や分配ロジックそのものは規定しません。 あくまで、部分準備型トークンは、借入と利息を伴う経済モデルで運用されることが前提であり、その利益は非分離口座の保有者に還元される設計が望ましいという立場を示しているだけです。 実装方法は各プロトコルに委ねられています。

互換性

ERC20と互換性があります。

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

参考実装

FractionalReserveToken.sol
// The code below is provided only for illustration, DO NOT use it in production
contract FractionalReserveToken is ERC20, Ownable {

    event MintFractionalReserve(address indexed minter, address to, uint256 amount);
    event BurnFractionalReserve(address indexed burner, address from, uint256 amount);
    event SetSegregatedAccount(address account, bool segregated);

    /// @notice token supply in these accounts is not counted towards the reserve, and
    /// therefore, additional token supply cannot be minted against them.
    mapping(address => bool) public segregatedAccount;

    /// @notice ratio between the token that is available as cash (immediate redemption)
    /// and the total supply of the token.
    uint256 public requiredReserveRatio;

    uint256 public totalBorrowedSupply;

    constructor(
        string memory _name,
        string memory _symbol
    ) ERC20(_name, _symbol) Ownable(msg.sender) {}

    function fractionalReserveMint(address to, uint256 amount) external onlyOwner {
        _mint(to, amount);
        totalBorrowedSupply += amount;
        emit MintFractionalReserve(msg.sender, to, amount);

        uint256 reserveRatio = (totalSupply() - totalBorrowedSupply - segregatedSupply) * 1e18 / totalSupply();
        require(reserveRatio >= requiredReserveRatio, "reserveRatio");
    }
    function fractionalReserveBurn(address from, uint256 amount) external onlyOwner {
        _burn(from, amount);
        totalBorrowedSupply -= amount;
        emit BurnFractionalReserve(msg.sender, from, amount);
    }

    // ------------------------------------------------------------------------------
    // Code below is not part of the standard
    // ------------------------------------------------------------------------------
    uint256 internal segregatedSupply; // supply of segregated tokens

    function _update(address from, address to, uint256 value) internal override {
        // keep the reserve up to date on transfers
        if (!segregatedAccount[from] && segregatedAccount[to]) {
            segregatedSupply += value;
        }
        if (segregatedAccount[from] && !segregatedAccount[to]) {
            segregatedSupply -= value;
        }
        ERC20._update(from, to, value);
    }

    function mint(address account, uint256 value) external onlyOwner {
        _mint(account, value);
    }

    function burn(address account, uint256 value) external onlyOwner {
        _burn(account, value);
    }

    function setSegregatedAccount(address account, bool segregated) external onlyOwner {
        if (segregated) {
            require(!segregatedAccount[account], "segregated");
            segregatedSupply += balanceOf(account);
        } else {
            require(segregatedAccount[account], "!segregated");
            segregatedSupply -= balanceOf(account);
        }
        segregatedAccount[account] = segregated;
        emit SetSegregatedAccount(account, segregated);
    }

    function setRequiredReserveRatio(uint256 value) external onlyOwner {
        requiredReserveRatio = value;
    }
}

セキュリティ

ERC7770は、部分準備型(フラクショナルリザーブ)という金融モデルを前提としたトークン標準です。 このモデルは、銀行やレンディング市場と同様に、常に全発行量を即時償還可能な資産で裏付けているわけではありません。 そのため、構造的に以下のような経済的リスクを内包します。

  • 流動性不足による即時償還不能。
  • 担保価値の急落による実質的な債務超過。
  • 市場不安による取り付け騒ぎ(バンクラン)。
  • 価格乖離(デペッグ)による信用低下。

ERC7770は、これらのリスクが存在することを前提に設計されていますが、それらを「どのように防ぐか」、「どの水準まで許容するか」といった運用上の安全対策については、一切規定しません。

つまり、ERC7770のセキュリティに関する立ち位置は以下です。

観点 位置づけ
経済モデルの安全性 規定しない
担保率の適正水準 規定しない
清算ロジック 規定しない
金利設計 規定しない
バンクラン対策 規定しない
リスク情報の可視化 標準として提供する

ERC7770は、「部分準備という危険性を含む金融構造を、安全に管理するための共通インターフェース」を提供するだけであり、そのリスクをどう制御するかは、以下の主体の責任になります。

  • トークン発行者。
  • リスクキュレーター。
  • レンディング市場運営者。
  • ミント権限を持つコントラクトの設計者。

言い換えると、ERC7770は「危険な金融行為を安全にする規格」ではなく、危険性を正しく可視化して複数の金融主体が同じ前提で扱えるようにする規格です。

そのため、準備率の設定、担保の種類、清算条件、金利カーブ、保険メカニズムなどは、すべてプロトコルごとの経済設計とガバナンスに委ねられます。 標準は、それらを統一的に表現し、取得できるようにするだけで、正解を与えるものではありません。

この姿勢は、スマートコントラクトの安全性というよりも、金融システムとしての健全性が問題になる領域であり、ERC7770はその責任範囲を意図的に切り分けています。

引用

Yaron Velner (@yaronvel), "ERC-7770: Fractional Reserve Token [DRAFT]," Ethereum Improvement Proposals, no. 7770, September 2024. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7770.

最後に

今回は「レンディングによってトークン供給を増やしつつ、準備金の割合から安全性や償還可能性を判断できる仕組みを提案しているERC7770」についてまとめてきました! いかがだったでしょうか?

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

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