はじめに

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

今回は、ブロックチェーン上で企業が自社の財務情報を公開できるようにするための、オンチェーン財務報告の標準規格を定義しているERC7776についてまとめていきます!

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

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

概要

ERC7776は、EVM(Ethereum Virtual Machine。Etherum互換の仮想実行環境)系ブロックチェーン上の企業(「プロトコル」とも呼びます)が、自社の財務情報――とくに損益計算書(Income Statement)と貸借対照表(Balance Sheet)――をオンチェーン(ブロックチェーン上に直接記録すること)で公開するための標準APIを提案しています。 公開手段はSolidityスマートコントラクト(Etherueum上で動くプログラム)で提供し、投資家が透明でアクセスしやすい形で数値を確認できるようにします。

狙いは、SECのForm 10-Q(米国の四半期報告書)に代表される、伝統的な株式市場の報告構造をブロックチェーンに取り入れることです。 公開される財務情報には、売上高(Revenue)、売上原価(Cost of Goods Sold: COGS)、営業費用(Operating Expenses)、営業利益(Operating Income)、EBITDA(利息・税金・減価償却・償却前利益)、EPS(Earnings Per Share-Token。1トークン当たり利益の考え方)が含まれ、投資家は標準化され、透明で明確かつ信頼できるフォーマットでプロトコルの健全性を評価できます。

下の表は、ERC7776が対象とする主な指標と意味合いです。

指標 説明
売上高(Revenue) 事業活動による総収入です。
売上原価(COGS) 商品・サービスを提供するために直接かかったコストです。
営業費用(Operating Expenses) 人件費やマーケ費など、継続的な運営コストです。
営業利益(Operating Income) 売上高からCOGSと営業費用を差し引いた利益です。
EBITDA 営業利益に減価償却等を加え、資本構成や税制の影響を除いた稼ぐ力を示します。
EPS(Share-Token 当たり利益) 総利益を流通トークン数で割った指標で、トークン単位の収益力を示します。

また、情報をオンチェーンに載せることで、誰でも同じデータにアクセスでき、改ざん耐性が高い状態で保てるというブロックチェーンの利点を活かします。

動機

ERC7776の動機は、暗号資産投資市場に実証的で透明な評価軸をもたらすことです。 現在、多くのトークン投資の判断材料は抽象的で定量性に乏しく、断片的な説明や意見に依存しがちです。 標準APIを通じて、プロトコルが自らの実数値の財務データをオンチェーンで一貫して公開できるようにすれば、投資家は推測ではなく事実に基づいて比較・評価できるようになります。 これは、暗号資産市場に対する信頼を高め、伝統的な株式市場に近い分析基準へと近づける取り組みです。

また、多くのERC20トークンは、上場株式の「持分(エクイティ)」とは性質が異なる点が課題です。 株式は企業の所有権の一部を表し、配当や利益分配の期待が明確に紐づきます。 一方で多くのプロトコルトークンは、プラットフォーム内で消費される「利用券」や「燃料」に近い性格を持ち、コモディティ(原油のような消費財)に似た振る舞いをします。 にもかかわらず、トークンは「プロトコルの代表」として宣伝・売買される一方で、上場株式のような公開・透明・明確な財務情報が用意されていないことが多いのが実情です。

さらに、インターネット上で見られるトークン分析は、SubstackやX(旧Twitter)の個人投稿など非公式で匿名性の高いものに偏りがちで、透明な財務数値やファクトが十分に示されていないケースが少なくありません。 これでは、投資家は定量的な裏付けを持つ判断が難しくなります。

ERC7776は、プロトコルが標準化された方法で数値を提示する道筋を提供し、投資家が透明で明確な財務情報をもとに投資判断を下せる環境を整えます。 その結果として、長期的な信頼・透明性・真剣さが暗号資産投資市場に根づくことを目指します。

参考表:株式と多くのトークンの性質の違い

観点 上場株式 多くのERC20トークン
本質 企業の所有権の一部です。 プラットフォーム内で使うための「消費・利用の単位」に近い性質です。
情報開示 10-Qのような公的で体系化された財務開示が前提です。 体系的な財務開示がない場合が多く、数値の透明性が不足しがちです。
投資家の評価軸 収益性や財務健全性など定量的な指標に依拠します。 仕様説明や将来像など抽象的情報に依存しがちです。

上記のように、ERC7776は「オンチェーンでの標準化された財務開示」という仕組みを通じて、プロトコルと投資家の情報の非対称性を減らし、暗号資産市場の評価基準を明確で比較可能な数値ベースに近づけることを目指しています。 これにより、プロジェクトの実態に即した健全な資本配分が促され、エコシステム全体の成熟につながることが期待されます。

仕様

実装要件

すべての実装は、以下の条件を満たす必要があります。

要件 説明
ERC20の実装 トークンを株式のように扱うため、ERC20規格を必ず実装する必要があります。これにより、トークン保有量=持分として扱えるようになります。
表示通貨 すべての財務数値(売上、原価、営業利益、EBITDAなど)は、対象プロトコルが選択したステーブルコイン(価格変動の少ない仮想通貨)を単位として表示します。
メタデータの拡張 ERC20のオプションメタデータ拡張を実装する必要があります。name と symbol は、元トークン名やシンボルと関連づけられるべきです。
メソッドの可視性 すべての関数は external 可視性を持ちます。これは、外部コントラクトやユーザーが直接呼び出せるようにするためです。
出力単位 関数が返す財務数値は、指定されたステーブルコイン建てで表示されます。
外部コントラクトの利用条件 他のスマートコントラクトのデータを参照する場合、そのコントラクトはブロックチェーンエクスプローラー上で検証済みかつソースコードが公開されていることが必須です。
タイムスタンプ制約 すべての関数は startTimestamp が endTimestamp 以下でなければなりません。両者が等しい場合は貸借対照表(スナップショット)を返し、異なる場合は損益計算書(期間報告)を返します。
出力構造体(Struct) 各関数の出力は単一の uint256 ではなく、複数の uint256 値を含む構造体(Struct)として返されます。これにより詳細なデータ提供が可能になります。

用語の定義

用語 説明
Currency(通貨) 財務情報の評価に使用されるステーブルコイン。
Revenue(売上高) 商品やサービス販売による総収益。
Cost of Goods Sold(売上原価) 商品やサービス提供に直接かかるコスト(労務費や材料費など)。
Operating Expenses(営業費用) 一般管理費、販売費、研究開発費など、継続的な運営コスト。
Operating Income(営業利益) 売上高から原価と営業費用を差し引いた利益。
EBITDA 利息、税金、減価償却、償却前利益。
Other Income and Expenses(営業外収益・費用) 金融収益や投資損益などの非営業的な収益・費用。
Net Income(純利益) すべての費用・税金を控除した最終利益。
EPS(1トークン当たり利益) 純利益を発行済みERC20トークン数で割った指標。

関数

stablecoinAddress

javascript
function stablecoinAddress() external view returns (address currencyAddress);

財務情報の評価に使われているステーブルコインのアドレスを返す関数。 この関数は、財務数値がどのステーブルコイン建てで表されているかを明確にするために使用します。 例えば、USDCやDAIなど、どの通貨で評価されているかを確認することができます。

戻り値

  • currencyAddress
    • ステーブルコインのコントラクトアドレス。

revenue

javascript
function revenue(uint256 startTimestamp, uint256 endTimestamp)
    external view returns (RevenueStruct);

指定した期間における売上高を返す関数。 この関数は、指定された期間内にプロトコルが得た総売上額を返します。 追加の詳細情報を含めるために、複数のフィールドを持つ構造体を返します。

引数

  • startTimestamp
    • 期間の開始時刻(UNIXタイム)。
  • endTimestamp
    • 期間の終了時刻(UNIXタイム)。

戻り値

  • RevenueStruct
    • grossRevenue 総売上高。
    • optionalAdditionalRevenueDetail1〜N 任意の追加売上項目。

cogs

javascript
function cogs(uint256 startTimestamp, uint256 endTimestamp)
    external view returns (COGSStruct);

指定した期間の売上原価(COGS)を返す関数。 この関数は、商品やサービスを提供する際に発生した直接コスト(材料費、労働費など)を集計して返します。

引数

  • startTimestamp
    • 開始時刻。
  • endTimestamp
    • 終了時刻。

戻り値

  • COGSStruct
    • totalCOGS 総売上原価。
    • optionalAdditionalCOGSDetail1〜N 任意の追加原価情報。

operatingExpenses

javascript
function operatingExpenses(uint256 startTimestamp, uint256 endTimestamp)
    external view returns (OperatingExpensesStruct);

指定期間内の営業費用を返す関数。 この関数は、プロトコル運営にかかる人件費、マーケティング費、研究開発費などの合計を返します。

引数

  • startTimestamp
    • 開始時刻。
  • endTimestamp
    • 終了時刻。

戻り値

  • OperatingExpensesStruct
    • totalOperatingExpenses 総営業費用。
    • optionalAdditionalExpenseDetail1〜N 任意の追加費用項目。

operatingIncome

javascript
function operatingIncome(uint256 startTimestamp, uint256 endTimestamp)
    external view returns (OperatingIncomeStruct);

営業利益を返す関数。 売上高から売上原価と営業費用を引いた結果を返します。 営業活動からの純粋な利益を示します。

引数

  • startTimestamp
    • 開始時刻。
  • endTimestamp
    • 終了時刻。

戻り値

  • OperatingIncomeStruct
    • totalOperatingIncome 総営業利益。
    • optionalAdditionalIncomeDetail1〜N 任意の補足項目。

ebitda

javascript
function ebitda(uint256 startTimestamp, uint256 endTimestamp)
    external view returns (EBITDAstruct);

EBITDA(利息・税金・減価償却前利益)を返す関数。 企業の本業によるキャッシュ創出能力を評価するために使用されます。 非現金費用や税効果を除外することで、事業活動自体の収益力を測ります。

引数

  • startTimestamp
    • 開始時刻。
  • endTimestamp
    • 終了時刻。

戻り値

  • EBITDAstruct
    • totalEBITDA 総EBITDA。
    • optionalAdditionalEBITDADetail1〜N 任意の補足項目。

otherIncomeExpenses

javascript
function otherIncomeExpenses(uint256 startTimestamp, uint256 endTimestamp)
    external view returns (OtherIncomeExpensesStruct);

営業外収益および費用を返す関数。 投資損益、金利収入・支出など、営業活動以外で発生した収益または費用を返します。

引数

  • startTimestamp
    • 開始時刻。
  • endTimestamp
    • 終了時刻。

戻り値

  • OtherIncomeExpensesStruct
    • totalOtherIncome 営業外収益。
    • totalOtherExpenses 営業外費用。
    • totalOtherIncomeDetail1〜N 収益の詳細項目。
    • totalOtherExpensesDetail1〜N 費用の詳細項目。

netIncome

javascript
function netIncome(uint256 startTimestamp, uint256 endTimestamp)
    external view returns (NetIncomeStruct);

純利益を返す関数。 営業利益と営業外損益から税金や減価償却などを差し引いた最終利益を算出します。

引数

  • startTimestamp
    • 開始時刻。
  • endTimestamp
    • 終了時刻。

戻り値

  • NetIncomeStruct
    • totalNetIncome 総純利益。
    • optionalAdditionalNetIncomeDetail1〜N 任意の補足項目。

earningsPerShare

javascript
function earningsPerShare(uint256 startTimestamp, uint256 endTimestamp)
    external view returns (EPSstruct);

1トークンあたりの利益(EPS)を返す関数。 プロトコルが発行したERC20トークン1単位あたりに帰属する利益を算出します。 株式市場のEPSと同様の意味を持ちます。

引数

  • startTimestamp
    • 開始時刻。
  • endTimestamp
    • 終了時刻。

戻り値

  • EPSstruct
    • basicEPS 基本EPS。
    • dilutedEPS 希薄化後EPS。
    • EPSDetail1〜N 任意の補足項目。

fullFinancialReport

javascript
function fullFinancialReport(uint256 startTimestamp, uint256 endTimestamp)
    external view returns (FullFinancialsStruct);

すべての財務項目をまとめた完全な財務レポートを返す関数。 売上、原価、営業費用、営業利益、EBITDA、営業外収益・費用、純利益、EPSといったすべての情報を一つの構造体にまとめて返します。 投資家や監査者はこの一括出力を用いることで、プロトコルの財務状況を包括的に把握できます。

引数

  • startTimestamp
    • 開始時刻。
  • endTimestamp
    • 終了時刻。

戻り値

  • FullFinancialsStruct
    • RevenueStruct など、すべての構造体が統合された形式。

補足

ERC20を採用する理由

ERC7776では、すべての実装においてERC20準拠が必須とされています。 これは、「トークンあたりの利益(Earnings Per Token)」の計算が、ERC20トークンの発行量や保有量と直接的に結びついているため**です。

つまり、各アカウントがどれだけのトークンを持っているかという情報は、利益分配やEPSの算出に不可欠です。 そのため、ERC20トークン標準を用いることで、計算や管理を一貫性のある形で行うことができます。

ERC20を前提にすることで、以下のような利点があります。

項目 説明
互換性 既存のウォレットやDeFiプロトコルなど、ERC20対応インターフェースと容易に連携できます。
標準化 どのプロトコルでも同じ構造で財務情報を提供でき、データ比較が容易になります。
会計一貫性 トークン数と利益の関係が明確になるため、EPSなどの算出が統一的に可能になります。

この設計方針により、透明な財務報告(Transparent Financial Statements) はあらゆるERC20ベースのプロジェクトに統合可能になります。 つまり、プロトコルの設計に依存せず、既存のトークン経済システムに組み込める汎用性を持つことが意図されています。

財務情報の二重提供:スナップショットと期間報告

この標準では、プロトコルが財務情報を以下の2つの形式で提供できるように設計されています。

提供形式 内容 利用目的
貸借対照表(Balance Sheet) ある時点(単一のブロックタイムスタンプ)での財務状態をスナップショットとして提供。 現在の資産・負債・純資産の状況を把握したい場合。
損益計算書(Income Statement) 2つのブロックタイムスタンプ間の財務変化を記録。 特定の期間における収益や支出の動きを追跡したい場合。

この仕組みにより、投資家や監査者は「現時点の財務状況」と「一定期間での収益推移」のどちらも確認できます。

具体的には、コントラクト呼び出し時の引数 startTimestamp と endTimestamp の値に応じて、返されるデータの性質が変わります。

条件 戻り値の意味
startTimestamp == endTimestamp 貸借対照表(スナップショット):ある一時点での財務状況を返す。
startTimestamp < endTimestamp 損益計算書:指定した期間における財務変化を返す。

この柔軟な設計により、単一のインターフェースから両方の財務視点を取得できるようになっています。

他のスマートコントラクトとの連携設計

この仕様は、単体のスマートコントラクト内で全ての財務情報を管理することを前提としていません。 代わりに、同一プロトコル内に存在する他のスマートコントラクトと相互に連携し、そこから必要なデータを取得することを想定しています。

例えば、以下のような構成が考えられます。

flowchart LR
  A[プロトコルの主要コントラクト] --> B[会計データ管理コントラクト]
  A --> C[ステーブルコイン管理コントラクト]
  A --> D[ERC20トークン管理コントラクト]
  B --> A
  C --> A
  D --> A

このように、会計データを扱う専用コントラクトを分離し、透明性と責任分担を明確化できます。 データを他のコントラクトから取得する場合、それらのコントラクトはブロックチェーンエクスプローラー上で検証済み(verified)であり、ソースコードが公開されていることが必須です。 これにより、データの真正性や不正操作の防止が保証されます。

互換性

ERC20と互換性があります。

参考実装

js
// SPDX-License-Identifier: CC0-1.0
pragma solidity 0.8.27;

interface IERC20 {
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
}

contract TransparentFinancialStatements {

    address public stablecoin;

    struct RevenueStruct {
        uint256 grossRevenue;
        uint256 optionalAdditionalRevenueDetail1;
        uint256 optionalAdditionalRevenueDetailN;
    }

    struct COGSStruct {
        uint256 totalCOGS;
        uint256 optionalAdditionalCOGSDetail1;
        uint256 optionalAdditionalCOGSDetailN;
    }

    struct OperatingExpensesStruct {
        uint256 totalOperatingExpenses;
        uint256 optionalAdditionalExpenseDetail1;
        uint256 optionalAdditionalExpenseDetailN;
    }

    struct OperatingIncomeStruct {
        uint256 totalOperatingIncome;
        uint256 optionalAdditionalIncomeDetail1;
        uint256 optionalAdditionalIncomeDetailN;
    }

    struct EBITDAstruct {
        uint256 totalEBITDA;
        uint256 optionalAdditionalEBITDADetail1;
        uint256 optionalAdditionalEBITDADetailN;
    }

    struct OtherIncomeExpensesStruct {
        uint256 totalOtherIncome;
        uint256 totalOtherExpenses;
        uint256 totalOtherIncomeDetail1;
        uint256 totalOtherExpensesDetail1;
        uint256 totalOtherIncomeDetailN;
        uint256 totalOtherExpensesDetailN;
    }

    struct NetIncomeStruct {
        uint256 totalNetIncome;
        uint256 optionalAdditionalNetIncomeDetail1;
        uint256 optionalAdditionalNetIncomeDetailN;
    }

    struct EPSstruct {
        uint256 basicEPS;
        uint256 dilutedEPS;
        uint256 EPSDetail1;
        uint256 EPSDetailN;
    }

    struct FullFinancialsStruct {
        RevenueStruct revenue;
        COGSStruct cogs;
        OperatingExpensesStruct operatingExpenses;
        OperatingIncomeStruct operatingIncome;
        EBITDAstruct ebitda;
        OtherIncomeExpensesStruct otherIncomeExpenses;
        NetIncomeStruct netIncome;
        EPSstruct eps;
    }

    constructor(address _stablecoin) {
        stablecoin = _stablecoin;
    }

    function currency() public view returns (address) {
        return stablecoin;
    }

    function revenue(uint256 startTimestamp, uint256 endTimestamp) 
        public 
        view 
        returns (RevenueStruct memory) 
    {
        require(startTimestamp <= endTimestamp, "Invalid timestamps");
        // Logic to calculate and return revenue details
        return RevenueStruct(1000, 500, 100); // Example values
    }

    function cogs(uint256 startTimestamp, uint256 endTimestamp) 
        public 
        view 
        returns (COGSStruct memory) 
    {
        require(startTimestamp <= endTimestamp, "Invalid timestamps");
        // Logic to calculate and return COGS details
        return COGSStruct(400, 150, 50); // Example values
    }

    function operatingExpenses(uint256 startTimestamp, uint256 endTimestamp) 
        public 
        view 
        returns (OperatingExpensesStruct memory) 
    {
        require(startTimestamp <= endTimestamp, "Invalid timestamps");
        // Logic to calculate and return operating expenses details
        return OperatingExpensesStruct(300, 100, 50); // Example values
    }

    function operatingIncome(uint256 startTimestamp, uint256 endTimestamp) 
        public 
        view 
        returns (OperatingIncomeStruct memory) 
    {
        require(startTimestamp <= endTimestamp, "Invalid timestamps");
        // Logic to calculate and return operating income details
        return OperatingIncomeStruct(300, 100, 50); // Example values
    }

    function ebitda(uint256 startTimestamp, uint256 endTimestamp) 
        public 
        view 
        returns (EBITDAstruct memory) 
    {
        require(startTimestamp <= endTimestamp, "Invalid timestamps");
        // Logic to calculate and return EBITDA details
        return EBITDAstruct(700, 200, 100); // Example values
    }

    function otherIncomeExpenses(uint256 startTimestamp, uint256 endTimestamp) 
        public 
        view 
        returns (OtherIncomeExpensesStruct memory) 
    {
        require(startTimestamp <= endTimestamp, "Invalid timestamps");
        // Logic to calculate and return other income/expenses details
        return OtherIncomeExpensesStruct(100, 50, 20, 10, 30, 20); // Example values
    }

    function netIncome(uint256 startTimestamp, uint256 endTimestamp) 
        public 
        view 
        returns (NetIncomeStruct memory) 
    {
        require(startTimestamp <= endTimestamp, "Invalid timestamps");
        // Logic to calculate and return net income details
        return NetIncomeStruct(600, 200, 100); // Example values
    }

    function earningsPerShare(uint256 startTimestamp, uint256 endTimestamp) 
        public 
        view 
        returns (EPSstruct memory) 
    {
        require(startTimestamp <= endTimestamp, "Invalid timestamps");
        // Logic to calculate and return EPS details
        return EPSstruct(10, 8, 2, 1); // Example values
    }

    function fullFinancialReport(uint256 startTimestamp, uint256 endTimestamp) 
        public 
        view 
        returns (FullFinancialsStruct memory) 
    {
        require(startTimestamp <= endTimestamp, "Invalid timestamps");
        // Logic to calculate and return all financial details
        return FullFinancialsStruct(
            revenue(startTimestamp, endTimestamp),
            cogs(startTimestamp, endTimestamp),
            operatingExpenses(startTimestamp, endTimestamp),
            operatingIncome(startTimestamp, endTimestamp),
            ebitda(startTimestamp, endTimestamp),
            otherIncomeExpenses(startTimestamp, endTimestamp),
            netIncome(startTimestamp, endTimestamp),
            earningsPerShare(startTimestamp, endTimestamp)
        );
    }
}

セキュリティ

重要な財務データをオンチェーンで表示するため、データの正確性とセキュリティ、特に主要な財務数値の改ざんや操作を防止することに注意を払う必要があります。

引用

Ignacio Ceaglio (@Nachoxt17) ignacioceaglio@gmail.com, "ERC-7776: Transparent Financial Statements [DRAFT]," Ethereum Improvement Proposals, no. 7776, September 2024. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7776.

最後に

今回は「ブロックチェーン上で企業が自社の財務情報を公開できるようにするための、オンチェーン財務報告の標準規格を定義しているERC7776」についてまとめてきました! いかがだったでしょうか?

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

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