LoginSignup
1
0

[EIP7092] 債券のトークン化を簡素化する新たな標準の仕組みを理解しよう!

Posted at

はじめに

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

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

今回は、伝統的な債券の特徴を維持しつつ、債券のトークン化を簡素化することを目的とした新しいERC標準の仕組みを提案しているEIP7092についてまとめていきます!
債券の発行、転送、償還などの操作を効率化し、コストを削減します。
また、クロスチェーン機能により、異なるブロックチェーン間での債券の移転と管理が可能になります。

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

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

概要

この提案は、固定利付き金融債券に関するものです。
この債券には、以下のような主要な特徴があります。

  • プライマリー市場での債券発行を容易にするための特徴が定義されて、新規債券の発行がスムーズになります。
  • セカンダリー市場での債券の売買を可能にする特徴も備えて、既に発行された債券の流通性が向上します。
  • 複数のブロックチェーンをまたいだ債券のオペレーションと管理を実現するクロスチェーン機能を提供し、異なるブロックチェーン間での債券の移転や管理が可能になります。

この提案は、発行、流通、管理の全てのフェーズにおいて利便性と柔軟性を高めることを目的とした、革新的な固定利付き債券の標準を導入するものです。
複数のブロックチェーンに対応することで、債券市場のさらなる発展と効率化が期待できます。

動機

この提案の背景には、以下のような問題意識があります。

固定利付き金融商品は、企業や他の組織が資金調達に広く利用している資産クラスです。
しかし、債券のトークン化への移行には課題があります。

既存の標準であるERC3475は、馴染みのない概念を導入しており、不必要なガス消費につながっています。
これがトークン化への障壁となっています。

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

ERC3475では、クーポン、満期日、元本などの名前付き変数がありません。
そのため、開発者はどのメタデータがどのパラメータに割り当てられているかを覚える必要があり、実装が難しくなっています。

つまり、現在の標準では、債券のトークン化に伴う概念の複雑さや、実装の難しさが問題となっています。
このことが、固定利付き商品のトークン化を妨げる要因になっていると指摘しています。

この提案は、これらの課題を解決し、よりシンプルで実装しやすい標準を導入することで、債券のトークン化を促進することを目的としていると理解できます。

仕様

コード
// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.0;

/**
* @title ERC-7092 Financial Bonds Standard
*/
interface IERC7092 /** is ERC165 */ {
    // events
    /**
    * @notice MUST be emitted when bond tokens are transferred, issued or redeemed, except during contract creation
    * @param _from the account that owns bonds
    * @param _to the account that receives the bond
    * @param _amount amount of bond tokens to be transferred
    */
    event Transfer(address indexed _from, address indexed _to, uint256 _amount);

    /**
    * @notice MUST be emitted when an account is approved or when the allowance is decreased
    * @param _owner bond token's owner
    * @param _spender the account to be allowed to spend bonds
    * @param _amount amount of bond tokens allowed by _owner to be spent by `_spender`
    *        Or amount of bond tokens to decrease allowance from `_spender`
    */
    event Approval(address indexed _owner, address indexed _spender, uint256 _amount);

    /**
    * @notice MUST be emitted when multiple bond tokens are transferred, issued or redeemed, with the exception being during contract creation
    * @param _from array of bondholders accounts
    * @param _to array of accounts to transfer bonds to
    * @param _amount array of amounts of bond tokens to be transferred
    *
    ** OPTIONAL - interfaces and other contracts MUST NOT expect this function to be present. MUST be emitted in `batchTransfer` and `batchTransferFrom` functions
    */
    event TransferBatch(address[] _from, address[] _to, uint256[] _amount);

    /**
    * @notice MUST be emitted when multiple accounts are approved or when the allowance is decreased from multiple accounts
    * @param _owner bondholder account
    * @param _spender array of accounts to be allowed to spend bonds, or to decrase the allowance from
    * @param _amount array of amounts of bond tokens allowed by `_owner` to be spent by multiple accounts in `_spender`.
    *
    ** OPTIONAL - interfaces and other contracts MUST NOT expect this function to be present. MUST be emitted in `batchApprove` and `batchDecreaseAllowance` functions
    */
    event ApprovalBatch(address indexed _owner, address[] _spender, uint256[] _amount);

    // getter functions
    /**
    *  @notice Returns the bond isin
    */
    function isin() external view returns(string memory);

    /**
    * @notice Returns the bond name
    */
    function name() external view returns(string memory);

    /**
    * @notice Returns the bond symbol
    *         It is RECOMMENDED to represent the symbol as a combination of the issuer Issuer'shorter name and the maturity date
    *         Ex: If a company named Green Energy issues bonds that will mature on october 25, 2030, the bond symbol could be `GE30` or `GE2030` or `GE102530`
    */
    function symbol() external view returns(string memory);

    /**
    * @notice Returns the bond currency. This is the contract address of the token used to pay and return the bond principal
    */
    function currency() external view returns(address);

    /**
    * @notice Returns the bond denominiation. This is the minimum amount in which the Bonds may be issued. It must be expressend in unit of the principal currency
    *         ex: If the denomination is equal to 1,000 and the currency is USDC, then the bond denomination is equal to 1,000 USDC
    */
    function denomination() external view returns(uint256);

    /**
    * @notice Returns the issue volume (total debt amount). It is RECOMMENDED to express the issue volume in denomination unit.
    */
    function issueVolume() external view returns(uint256);

    /**
    * @notice Returns the bond interest rate. It is RECOMMENDED to express the interest rate in basis point unit.
    *         1 basis point = 0.01% = 0.0001
    *         ex: if interest rate = 5%, then coupon() => 500 basis points
    */
    function couponRate() external view returns(uint256);

    /**
    * @notice Returns the date when bonds were issued to investors. This is a Unix Timestamp like the one returned by block.timestamp
    */
    function issueDate() external view returns(uint256);

    /**
    * @notice Returns the bond maturity date, i.e, the date when the pricipal is repaid. This is a Unix Timestamp like the one returned by block.timestamp
    *         The maturity date MUST be greater than the issue date
    */
    function maturityDate() external view returns(uint256);

    /**
    * @notice Returns the principal of an account. It is RECOMMENDED to express the principal in the bond currency unit (USDC, DAI, etc...)
    * @param _account account address
    */
    function principalOf(address _account) external view returns(uint256);

    /**
    * @notice Returns the amount of tokens the `_spender` account has been authorized by the `_owner``
    *         acount to manage their bonds
    * @param _owner the bondholder address
    * @param _spender the address that has been authorized by the bondholder
    */
    function allowance(address _owner, address _spender) external view returns(uint256);

    // setter functions
    /**
    * @notice Authorizes `_spender` account to manage `_amount`of their bond tokens
    * @param _spender the address to be authorized by the bondholder
    * @param _amount amount of bond tokens to approve
    */
    function approve(address _spender, uint256 _amount) external returns(bool);

    /**
    * @notice Lowers the allowance of `_spender` by `_amount`
    * @param _spender the address to be authorized by the bondholder
    * @param _amount amount of bond tokens to remove from allowance
    */
    function decreaseAllowance(address _spender, uint256 _amount) external returns(bool);

    /**
    * @notice Moves `_amount` bonds to address `_to`. This methods also allows to attach data to the token that is being transferred
    * @param _to the address to send the bonds to
    * @param _amount amount of bond tokens to transfer
    * @param _data additional information provided by the token holder
    */
    function transfer(address _to, uint256 _amount, bytes calldata _data) external returns(bool);

    /**
    * @notice Moves `_amount` bonds from an account that has authorized the caller through the approve function
    *         This methods also allows to attach data to the token that is being transferred
    * @param _from the bondholder address
    * @param _to the address to transfer bonds to
    * @param _amount amount of bond tokens to transfer.
    * @param _data additional information provided by the token holder
    */
    function transferFrom(address _from, address _to, uint256 _amount, bytes calldata _data) external returns(bool);

    // batch functions
    /**
    * @notice Authorizes multiple spender accounts to manage a specified `_amount` of the bondholder tokens
    * @param _spender array of accounts to be authorized by the bondholder
    * @param _amount array of amounts of bond tokens to approve
    *
    * OPTIONAL - interfaces and other contracts MUST NOT expect these values to be present. The method is used to improve usability.
    */
    function batchApprove(address[] calldata _spender, uint256[] calldata _amount) external returns(bool);

    /**
    * @notice Decreases the allowance of multiple spenders by corresponding amounts in `_amount`
    * @param _spender array of accounts to be authorized by the bondholder
    * @param _amount array of amounts of bond tokens to decrease the allowance from
    *
    * OPTIONAL - interfaces and other contracts MUST NOT expect this function to be present. The method is used to decrease token allowance.
    */
    function batchDecreaseAllowance(address[] calldata _spender, uint256[] calldata _amount) external returns(bool);

    /**
    * @notice Transfers multiple bonds with amounts specified in the array `_amount` to the corresponding accounts in the array `_to`, with the option to attach additional data
    * @param _to array of accounts to send the bonds to
    * @param _amount array of amounts of bond tokens to transfer
    * @param _data array of additional information provided by the token holder
    *
    * OPTIONAL - interfaces and other contracts MUST NOT expect this function to be present.
    */
    function batchTransfer(address[] calldata _to, uint256[] calldata _amount, bytes[] calldata _data) external returns(bool);

    /**
    * @notice Transfers multiple bonds with amounts specified in the array `_amount` to the corresponding accounts in the array `_to` from an account that have been authorized by the `_from` account
    *         This method also allows to attach data to tokens that are being transferred
    * @param _from array of bondholder accounts
    * @param _to array of accounts to transfer bond tokens to
    * @param _amount array of amounts of bond tokens to transfer.
    * @param _data array of additional information provided by the token holder
    *
    ** OPTIONAL - interfaces and other contracts MUST NOT expect this function to be present.
    */
    function batchTransferFrom(address[] calldata _from, address[] calldata _to, uint256[] calldata _amount, bytes[] calldata _data) external returns(bool);
}

Transfer

event Transfer(address indexed _from, address indexed _to, uint256 _amount);

概要
債券トークンの転送、発行、償還時に発行されるイベント。

詳細
コントラクトの作成時を除き、債券トークンが転送、発行、または償還されたときに発行されなければなりません。

パラメータ

  • _from
    • 債券を所有するアカウントのアドレス。
  • _to
    • 債券を受け取るアカウントのアドレス。
  • _amount
    • 転送される債券トークンの量。

Approval

event Approval(address indexed _owner, address indexed _spender, uint256 _amount);

概要
アカウントが承認されたとき、または許可量が減少したときに発行されるイベント。

詳細
アカウントが承認されたとき、または_spenderからの許可量が減少したときに発行されなければなりません。

パラメータ

  • _owner
    • 債券トークンの所有者のアドレス。
  • _spender
    • 債券を使用することを許可されるアカウントのアドレス。
  • _amount
    • _owner_spenderに使用を許可する債券トークンの量、または_spenderからの許可量を減少させる債券トークンの量。

TransferBatch

event TransferBatch(address[] _from, address[] _to, uint256[] _amount);

概要
複数の債券トークンが転送、発行、または償還されたときに発行されるイベント。

詳細
コントラクトの作成時を除き、複数の債券トークンが転送、発行、または償還されたときに発行されなければなりません。
このイベントはbatchTransferおよびbatchTransferFrom関数で発行されなければなりません。

パラメータ

  • _from
    • 債券保有者のアカウントアドレスの配列。
  • _to
    • 債券を転送する先のアカウントアドレスの配列。
  • _amount
    • 転送される債券トークンの量の配列。

ApprovalBatch

event ApprovalBatch(address indexed _owner, address[] _spender, uint256[] _amount);

概要
複数のアカウントが承認されたとき、または複数のアカウントからの許可量が減少したときに発行されるイベント。

詳細
複数のアカウントが承認されたとき、または複数のアカウントからの許可量が減少したときに発行されなければなりません。
このイベントはbatchApproveおよびbatchDecreaseAllowance関数で発行されなければなりません。

パラメータ

  • _owner
    • 債券保有者のアカウントアドレス。
  • _spender
    • 債券の使用を許可される、または許可量を減少させるアカウントアドレスの配列。
  • _amount
    • _owner_spender内の複数のアカウントに使用を許可する債券トークンの量の配列。

isin

function isin() external view returns(string memory);

概要
債券のISINコードを返す関数。

詳細
この関数は、債券のISIN(International Securities Identification Number)コードを返します。
ISINコードは、国際的に標準化された証券識別コードです。

戻り値

  • string memory
    • 債券のISINコード。

name

function name() external view returns(string memory);

概要
債券の名前を返す関数。

詳細
この関数は、債券の名前を返します。

戻り値

  • string memory
    • 債券の名前。

symbol

function symbol() external view returns(string memory);

概要
債券のシンボルを返す関数。

詳細
この関数は、債券のシンボルを返します。
シンボルは、発行者の短縮名と満期日の組み合わせで表現することが推奨されています。
例えば、Green Energyという会社が2030年10月25日に満期を迎える債券を発行する場合、債券のシンボルはGE30GE2030GE102530のようになります。

戻り値

  • string memory
    • 債券のシンボル。

currency

function currency() external view returns(address);

概要
債券の通貨を返す関数。

詳細
この関数は、債券の元本の支払いと返済に使用されるトークンのコントラクトアドレスを返します。

戻り値

  • address
    • 債券の通貨のコントラクトアドレス。

denomination

function denomination() external view returns(uint256);

概要
債券の最小発行単位を返す関数。

詳細
この関数は、債券の最小発行単位を返します。
最小発行単位は、元本通貨の単位で表現されなければなりません。
例えば、最小発行単位が1,000で通貨がUSDCの場合、債券の最小発行単位は1,000 USDCになります。

戻り値

  • uint256
    • 債券の最小発行単位。

issueVolume

function issueVolume() external view returns(uint256);

概要
債券の発行量(総債務額)を返す関数。

詳細
この関数は、債券の発行量(総債務額)を返します。
発行量は、最小発行単位で表現することが推奨されています。

戻り値

  • uint256
    • 債券の発行量。

couponRate

function couponRate() external view returns(uint256);

概要
債券の利率を返す関数。

詳細
この関数は、債券の利率を返します。
利率はベーシスポイント単位で表現することが推奨されています。
1ベーシスポイントは0.01%、つまり0.0001に等しいです。
例えば、利率が5%の場合、couponRate500ベーシスポイントを返します。

戻り値

  • uint256
    • 債券の利率(ベーシスポイント単位)。

issueDate

function issueDate() external view returns(uint256);

概要
債券が投資家に発行された日付を返す関数。

詳細
この関数は、債券が投資家に発行された日付を返します。
この日付は、block.timestampが返すようなUnixタイムスタンプです。

戻り値

  • uint256
    • 債券の発行日(Unixタイムスタンプ)。

maturityDate

function maturityDate() external view returns(uint256);

概要
債券の満期日を返す関数。

詳細
この関数は、元本が返済される債券の満期日を返します。
この日付は、block.timestampが返すようなUnixタイムスタンプです。
満期日は発行日より後でなければなりません。

戻り値

  • uint256
    • 債券の満期日(Unixタイムスタンプ)。

principalOf

function principalOf(address _account) external view returns(uint256);

概要
アカウントの元本を返す関数。

詳細
この関数は、指定されたアカウントの元本を返します。
元本は債券の通貨単位(USDC、DAIなど)で表現することが推奨されています。

引数

  • _account
    • アカウントのアドレス。

戻り値

  • uint256
    • アカウントの元本。

allowance

function allowance(address _owner, address _spender) external view returns(uint256);

概要
_ownerアカウントが_spenderアカウントに許可した債券の量を返す関数。

詳細
この関数は、_ownerアカウントが_spenderアカウントに管理を許可した債券の量を返します。

引数

  • _owner
    • 債券保有者のアドレス。
  • _spender
    • 債券保有者によって許可されたアドレス。

戻り値

  • uint256
    • _owner_spenderに許可した債券の量。

approve

function approve(address _spender, uint256 _amount) external returns(bool);

概要
_spenderアカウントに_amountの債券トークンの管理を許可する関数。

詳細
この関数は、債券保有者が_spenderアカウントに_amountの債券トークンの管理を許可します。

引数

  • _spender
    • 債券保有者によって許可されるアドレス。
  • _amount
    • 承認する債券トークンの量。

戻り値

  • bool
    • 承認が成功した場合はtrue、そうでない場合はfalse

decreaseAllowance

function decreaseAllowance(address _spender, uint256 _amount) external returns(bool);

概要
_spenderの許可量を_amount分減らす関数。

詳細
この関数は、債券保有者が_spenderの許可量を_amount分減らします。

引数

  • _spender
    • 債券保有者によって許可されるアドレス。
  • _amount
    • 許可量から減らす債券トークンの量。

戻り値

  • bool
    • 許可量の減少が成功した場合はtrue、そうでない場合はfalse

transfer

function transfer(address _to, uint256 _amount, bytes calldata _data) external returns(bool);

概要
_amountの債券を_toアドレスに移動する関数。

詳細
この関数は、_amountの債券を_toアドレスに移動します。
また、この関数では、転送されるトークンにデータを添付することもできます。

引数

  • _to
    • 債券を送信するアドレス。
  • _amount
    • 転送する債券トークンの量。
  • _data
    • トークン保有者が提供する追加情報。

戻り値

  • bool
    • 転送が成功した場合はtrue、そうでない場合はfalse

transferFrom

function transferFrom(address _from, address _to, uint256 _amount, bytes calldata _data) external returns(bool);

概要
approve関数を通じて呼び出し元に許可されたアカウントから_amountの債券を移動する関数。

詳細
この関数は、approve関数を通じて呼び出し元に許可されたアカウントから_amountの債券を移動します。
また、この関数では、転送されるトークンにデータを添付することもできます。

引数

  • _from
    • 債券保有者のアドレス。
  • _to
    • 債券を転送するアドレス。
  • _amount
    • 転送する債券トークンの量。
  • _data
    • トークン保有者が提供する追加情報。

戻り値

  • bool
    • 転送が成功した場合はtrue、そうでない場合はfalse

batchApprove

function batchApprove(address[] calldata _spender, uint256[] calldata _amount) external returns(bool);

概要
複数の_spenderアカウントに指定された_amountの債券保有者トークンの管理を許可する関数。

詳細
この関数は、債券保有者が複数の_spenderアカウントに指定された_amountの債券トークンの管理を許可します。
この関数は使いやすさを向上させるために使用されます。

引数

  • _spender
    • 債券保有者によって許可されるアカウントの配列。
  • _amount
    • 承認する債券トークンの量の配列。

戻り値

  • bool
    • 承認が成功した場合はtrue、そうでない場合はfalse

batchDecreaseAllowance

function batchDecreaseAllowance(address[] calldata _spender, uint256[] calldata _amount) external returns(bool);

概要
複数の_spenderの許可量を_amountに対応する量だけ減らす関数。

詳細
この関数は、複数の_spenderの許可量を_amountに対応する量だけ減らします。
この関数はトークンの許可量を減らすために使用されます。

引数

  • _spender
    • 債券保有者によって許可されるアカウントの配列。
  • _amount
    • 許可量から減らす債券トークンの量の配列。

戻り値

  • bool
    • 許可量の減少が成功した場合はtrue、そうでない場合はfalse

batchTransfer

function batchTransfer(address[] calldata _to, uint256[] calldata _amount, bytes[] calldata _data) external returns(bool);

概要
_amount配列で指定された量の複数の債券を、_to配列の対応するアカウントに転送し、追加データを添付することができる関数。

詳細
この関数は、_amount配列で指定された量の複数の債券を、_to配列の対応するアカウントに転送します。
また、トークン保有者が提供する追加データを添付することもできます。

引数

  • _to
    • 債券を送信するアカウントの配列。
  • _amount
    • 転送する債券トークンの量の配列。
  • _data
    • トークン保有者が提供する追加情報の配列。

戻り値

  • bool
    • 転送が成功した場合はtrue、そうでない場合はfalse

batchTransferFrom

function batchTransferFrom(address[] calldata _from, address[] calldata _to, uint256[] calldata _amount, bytes[] calldata _data) external returns(bool);

概要
_fromアカウントによって許可されたアカウントから、_amount配列で指定された量の複数の債券を、_to配列の対応するアカウントに転送する関数。

詳細
この関数は、_fromアカウントによって許可されたアカウントから、_amount配列で指定された量の複数の債券を、_to配列の対応するアカウントに転送します。
また、転送されるトークンにデータを添付することもできます。

引数

  • _from
    • 債券保有者のアカウントの配列。
  • _to
    • 債券トークンを転送するアカウントの配列。
  • _amount
    • 転送する債券トークンの量の配列。
  • _data
    • トークン保有者が提供する追加情報の配列。

戻り値

  • bool
    • 転送が成功した場合はtrue、そうでない場合はfalse

追加ボンド・パラメーター インターフェース

この提案は、IERC7092ESGインターフェースを通じて、追加の債券パラメータを定義しています。
このインターフェースは、標準の使いやすさを向上させるために使用することができますが、オプションであり、この提案を実装するコントラクトにとって必須ではありません。

提案されている追加のパラメータは以下の通りです。

currencyOfCoupon

クーポン(利払い)に使用される通貨を表します。
この通貨は、元本の返済に使用される通貨とは異なる場合があります。

couponType

発行者が投資家に支払うことを約束した利率の種類を示すために使用されます。
ゼロクーポン、固定金利、変動金利など、様々な形態を取ることができます。

couponFrequency

債券が利息を債券保有者に支払う頻度を指します。
通常、年間、半年ごと、四半期ごと、月間などの時間単位で表現されます。

dayCountBasis

2つのクーポン支払日またはその他の特定の期間の間の債券の経過利息を計算するために使用されます。
デイカウントベースには、Actual/Actual30/360Actual/360Actual/36530/365などがあります。

デイカウントベースは、債券の利息計算に用いられる日数計算の方法です。

Actual/Actual

実際の経過日数と実際の年日数(閏年は366日、平年は365日)に基づいて計算されます。
最も正確な計算方法ですが、計算が複雑になる可能性があります。

30/360

1ヶ月を30日、1年を360日として計算されます。
実際の日数とは異なりますが、計算が簡単で一貫性があるため、広く使用されています。
通常、米国の社債や米国政府機関債で使用されます。

Actual/360

実際の経過日数を360日で割って計算されます。
1年を360日とみなすため、利息額が若干高めに計算されます。
通常、米国の短期債や Money Market 商品で使用されます。

Actual/365

実際の経過日数を365日で割って計算されます。
1年を常に365日とみなすため、閏年の影響を受けません。
通常、英国や欧州で使用されます。

30/365

1ヶ月を30日、1年を365日として計算されます。
30/360と同様に、実際の日数とは異なりますが、計算が簡単で一貫性があります。
あまり一般的ではありませんが、一部の債券で使用されています。

デイカウントベースは、債券の発行市場や発行体によって異なります。
投資家は、債券の利息計算方法を理解し、異なる債券間の利回りを比較する際に考慮する必要があります。

これらの追加パラメータを使用することで、債券の特性をより詳細に定義することができ、投資家にとってより明確で透明性の高い情報を提供することができます。
また、これらのパラメータを標準化することで、異なる発行者や債券間の比較がより容易になり、市場の効率性が向上すると期待されます。

コード
// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.0;

interface IERC7092ESG /** is ERC165 */ {
    /**
    * @notice Returns the number of decimals used by the bond. For example, if it returns `10`, it means that the token amount MUST be multiplied by 10000000000 to get the standard representation.
    */
    function decimals() external view returns(uint8);

    /**
    * @notice Rreturns the coupon currency, which is represented by the contract address of the token used to pay coupons. It can be the same as the one used for the principal
    */
    function currencyOfCoupon() external view returns(address);

    /**
    * @notice Returns the coupon type
    *         For example, 0 can denote Zero coupon, 1 can denote Fixed Rate, 2 can denote Floating Rate, and so on
    */
    function couponType() external view returns(uint8);

    /**
    * @notice Returns the coupon frequency, i.e. the number of times coupons are paid in a year.
    */
    function couponFrequency() external view returns(uint256);

    /**
    * @notice Returns the day count basis
    *         For example, 0 can denote actual/actual, 1 can denote actual/360, and so on
    */
    function dayCountBasis() external view returns(uint8);
}

decimals

function decimals() external view returns(uint8);

概要
債券で使用される小数点以下の桁数を返す関数。

詳細
この関数は、債券で使用される小数点以下の桁数を返します。
例えば、10を返す場合、トークンの量に10000000000を掛けて標準表現を得る必要があることを意味します。

戻り値

  • uint8
    • 債券で使用される小数点以下の桁数。

currencyOfCoupon

function currencyOfCoupon() external view returns(address);

概要
クーポンの支払いに使用されるトークンのコントラクトアドレスを返す関数。

詳細
この関数は、クーポン(利払い)の支払いに使用されるトークンのコントラクトアドレスを返します。
これは、元本に使用されるものと同じである可能性があります。

戻り値

  • address
    • クーポンの支払いに使用されるトークンのコントラクトアドレス。

couponType

function couponType() external view returns(uint8);

概要
クーポンのタイプを返す関数。

詳細
この関数は、クーポンのタイプを返します。
例えば、0はゼロクーポン、1は固定金利、2は変動金利などを表すことができます。

戻り値

  • uint8
    • クーポンのタイプを表す数値。

couponFrequency

function couponFrequency() external view returns(uint256);

概要
クーポンの支払い頻度を返す関数。

詳細
この関数は、クーポンの支払い頻度、つまり1年間にクーポンが支払われる回数を返します。

戻り値

  • uint256
    • 1年間のクーポン支払い回数。

dayCountBasis

function dayCountBasis() external view returns(uint8);

概要
デイカウントベースを返す関数。

詳細
この関数は、デイカウントベースを返します。
例えば、0Actual/Actual1Actual/360などを表すことができます。

戻り値

  • uint8
    • デイカウントベースを表す数値。

クロスチェーンインターフェース

この標準では、債券トークンのクロスチェーン管理のために、IERC7092CrossChainインターフェースの実装を許可しています。
このインターフェースはオプションであり、クロスチェーントランザクションを可能にするためにアプリケーションで使用することができます。

クロスチェーントランザクションを開始する関数は、以下の2つのパラメータを明示的に定義しなければなりません。

  • destinationChainID

    • 宛先チェーンの識別子を指定します。
    • これにより、トランザクションがどのブロックチェーンに送信されるかが明確になります。
  • destinationContract

    • ターゲットとなるスマートコントラクトを指定します。
    • これにより、宛先チェーン上のどのスマートコントラクトがトランザクションを処理するかが明確になります。

これらのパラメータを明示的に定義することで、クロスチェーントランザクションのセキュリティと透明性が向上します。
宛先チェーンとターゲットコントラクトが明確に特定されるため、トランザクションが意図した通りに処理されることが保証されます。

IERC7092CrossChainインターフェースは、異なるブロックチェーン間での債券トークンの移転や管理を可能にすることで、債券市場の相互運用性と流動性を高めることを目的としています。
これにより、投資家はより幅広い選択肢を持ち、発行者は資金調達の機会を拡大することができます。

ただし、このインターフェースの実装はオプションであり、すべての債券コントラクトに必須ではありません。
クロスチェーン機能の必要性は、個々のユースケースによって異なります。

コード
// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.0;

interface IERC7092CrossChain /** is ERC165 */ {
    // events
    /**
    * @notice MUST be emitted when bond tokens are transferred or redeemed in a cross-chain transaction
    * @param _from bondholder account
    * @param _to account the transfer bond tokens to
    * @param _amount amount of bond tokens to be transferred
    * @param _destinationChainID The unique ID that identifies the destination Chain
    */
    event CrossChainTransfer(address indexed _from, address indexed _to, uint256 _amount, bytes32 _destinationChainID);

    /**
    * @notice MUST be emitted when several bond tokens are transferred or redeemed in a cross-chain transaction
    * @param _from array of bondholders accounts
    * @param _to array of accounts that receive the bond
    * @param _amount array of amount of bond tokens to be transferred
    * @param _destinationChainID array of unique IDs that identify the destination Chain
    */
    event CrossChainTransferBatch(address[] _from, address[] _to, uint256[] _amount, bytes32[] _destinationChainID);

    /**
    * @notice MUST be emitted when an account is approved to spend the bondholder's tokens in a different chain than the current chain
    * @param _owner the bondholder account
    * @param _spender the account to be allowed to spend bonds
    * @param _amount amount of bond tokens allowed by `_owner` to be spent by `_spender`
    * @param _destinationChainID The unique ID that identifies the destination Chain
    */
    event CrossChainApproval(address indexed _owner, address indexed _spender, uint256 _amount, bytes32 _destinationChainID);

    /**
    * @notice MUST be emitted when multiple accounts in the array `_spender` are approved or when the allowances of multiple accounts in the array `_spender` are reduced on the destination chain which MUST be different than the current chain
    * @param _owner bond token's owner
    * @param _spender array of accounts to be allowed to spend bonds
    * @param _amount array of amount of bond tokens allowed by _owner to be spent by _spender
    * @param _destinationChainID array of unique IDs that identify the destination Chain
    */
    event CrossChainApprovalBatch(address indexed _owner, address[] _spender, uint256[] _amount, bytes32[] _destinationChainID);

    // functions
    /**
    * @notice Authorizes the `_spender` account to manage a specified `_amount`of the bondholder bond tokens on the destination Chain
    * @param _spender account to be authorized by the bondholder
    * @param _amount amount of bond tokens to approve
    * @param _destinationChainID The unique ID that identifies the destination Chain.
    * @param _destinationContract The smart contract to interact with in the destination Chain
    */
    function crossChainApprove(address _spender, uint256 _amount, bytes32 _destinationChainID, address _destinationContract) external returns(bool);

    /**
    * @notice Authorizes multiple spender accounts in `_spender` to manage specified amounts in `_amount` of the bondholder tokens on the destination chain
    * @param _spender array of accounts to be authorized by the bondholder
    * @param _amount array of amounts of bond tokens to approve
    * @param _destinationChainID array of unique IDs that identifies the destination Chain.
    * @param _destinationContract array of smart contracts to interact with in the destination Chain in order to Deposit or Mint tokens that are transferred.
    */
    function crossChainBatchApprove(address[] calldata _spender, uint256[] calldata _amount, bytes32[] calldata _destinationChainID, address[] calldata _destinationContract) external returns(bool);

    /**
    * @notice Decreases the allowance of `_spender` by a specified `_amount` on the destination Chain
    * @param _spender the address to be authorized by the bondholder
    * @param _amount amount of bond tokens to remove from allowance
    * @param _destinationChainID The unique ID that identifies the destination Chain.
    * @param _destinationContract The smart contract to interact with in the destination Chain in order to Deposit or Mint tokens that are transferred.
    */
    function crossChainDecreaseAllowance(address _spender, uint256 _amount, bytes32 _destinationChainID, address _destinationContract) external returns(bool);

    /**
    * @notice Decreases the allowance of multiple spenders in `_spender` by corresponding amounts specified in the array `_amount` on the destination chain
    * @param _spender array of accounts to be authorized by the bondholder
    * @param _amount array of amounts of bond tokens to decrease the allowance from
    * @param _destinationChainID array of unique IDs that identifies the destination Chain.
    * @param _destinationContract array of smart contracts to interact with in the destination Chain in order to Deposit or Mint tokens that are transferred.
    */
    function crossChainBatchDecreaseAllowance(address[] calldata _spender, uint256[] calldata _amount, bytes32[] calldata _destinationChainID, address[] calldata _destinationContract) external returns(bool);

    /**
    * @notice Moves `_amount` bond tokens to the address `_to` from the current chain to another chain (e.g., moving tokens from Ethereum to Polygon).
    *         This methods also allows to attach data to the token that is being transferred
    * @param _to account to send bond tokens to
    * @param _amount amount of bond tokens to transfer
    * @param _data additional information provided by the bondholder
    * @param _destinationChainID The unique ID that identifies the destination Chain.
    * @param _destinationContract The smart contract to interact with in the destination Chain in order to Deposit or Mint bond tokens that are transferred.
    */
    function crossChainTransfer(address _to, uint256 _amount, bytes calldata _data, bytes32 _destinationChainID, address _destinationContract) external returns(bool);

    /**
    * @notice Transfers multiple bond tokens with amounts specified in the array `_amount` to the corresponding accounts in the array `_to` from the current chain to another chain (e.g., moving tokens from Ethereum to Polygon).
    *         This methods also allows to attach data to the token that is being transferred
    * @param _to array of accounts to send the bonds to
    * @param _amount array of amounts of bond tokens to transfer
    * @param _data array of additional information provided by the bondholder
    * @param _destinationChainID array of unique IDs that identify the destination Chains.
    * @param _destinationContract array of smart contracts to interact with in the destination Chains in order to Deposit or Mint bond tokens that are transferred.
    */
    function crossChainBatchTransfer(address[] calldata _to, uint256[] calldata _amount, bytes[] calldata _data, bytes32[] calldata _destinationChainID, address[] calldata _destinationContract) external returns(bool);

    /**
    * @notice Transfers `_amount` bond tokens from the `_from`account to the `_to` account from the current chain to another chain. The caller must be approved by the `_from` address.
    *         This methods also allows to attach data to the token that is being transferred
    * @param _from the bondholder address
    * @param _to the account to transfer bonds to
    * @param _amount amount of bond tokens to transfer
    * @param _data additional information provided by the token holder
    * @param _destinationChainID The unique ID that identifies the destination Chain.
    * @param _destinationContract The smart contract to interact with in the destination Chain in order to Deposit or Mint tokens that are transferred.
    */
    function crossChainTransferFrom(address _from, address _to, uint256 _amount, bytes calldata _data, bytes32 _destinationChainID, address _destinationContract) external returns(bool);

    /**
    * @notice Transfers several bond tokens with amounts specified in the array `_amount` from accounts in the array `_from` to accounts in the array `_to` from the current chain to another chain.
    *         The caller must be approved by the `_from` accounts to spend the corresponding amounts specified in the array `_amount`
    *         This methods also allows to attach data to the token that is being transferred
    * @param _from array of bondholder addresses
    * @param _to array of accounts to transfer bonds to
    * @param _amount array of amounts of bond tokens to transfer
    * @param _data array of additional information provided by the token holder
    * @param _destinationChainID array of unique IDs that identifies the destination Chain.
    * @param _destinationContract array of smart contracts to interact with in the destination Chain in order to Deposit or Mint tokens that are transferred.
    */
    function crossChainBatchTransferFrom(address[] calldata _from, address[] calldata _to, uint256[] calldata _amount, bytes[] calldata _data, bytes32[] calldata _destinationChainID, address[] calldata _destinationContract) external returns(bool);
}

CrossChainTransfer

event CrossChainTransfer(address indexed _from, address indexed _to, uint256 _amount, bytes32 _destinationChainID);

概要
債券トークンがクロスチェーントランザクションで転送または償還されたときに発行されるイベント。

詳細
債券トークンがクロスチェーントランザクションで転送または償還されたときに発行されなければなりません。

パラメータ

  • _from
    • 債券保有者のアカウントアドレス。
  • _to
    • 債券トークンの転送先アカウントのアドレス。
  • _amount
    • 転送される債券トークンの量。
  • _destinationChainID
    • 宛先チェーンを識別するユニークなID。

CrossChainTransferBatch

event CrossChainTransferBatch(address[] _from, address[] _to, uint256[] _amount, bytes32[] _destinationChainID);

概要
複数の債券トークンがクロスチェーントランザクションで転送または償還されたときに発行されるイベント。

詳細
複数の債券トークンがクロスチェーントランザクションで転送または償還されたときに発行されなければなりません。

パラメータ

  • _from
    • 債券保有者のアカウントアドレスの配列。
  • _to
    • 債券を受け取るアカウントのアドレスの配列。
  • _amount
    • 転送される債券トークンの量の配列。
  • _destinationChainID
    • 宛先チェーンを識別するユニークなIDの配列。

CrossChainApproval

event CrossChainApproval(address indexed _owner, address indexed _spender, uint256 _amount, bytes32 _destinationChainID);

概要
あるアカウントが、現在のチェーンとは異なるチェーンで債券保有者のトークンを使用することを承認されたときに発行されるイベント。

詳細
あるアカウントが、現在のチェーンとは異なるチェーンで債券保有者のトークンを使用することを承認されたときに発行されなければなりません。

パラメータ

  • _owner
    • 債券保有者のアカウントアドレス。
  • _spender
    • 債券の使用を許可されるアカウントのアドレス。
  • _amount
    • _owner_spenderに使用を許可する債券トークンの量。
  • _destinationChainID
    • 宛先チェーンを識別するユニークなID。

CrossChainApprovalBatch

event CrossChainApprovalBatch(address indexed _owner, address[] _spender, uint256[] _amount, bytes32[] _destinationChainID);

概要
_spender配列内の複数のアカウントが承認されたとき、または現在のチェーンとは異なる宛先チェーンで_spender配列内の複数のアカウントの許可量が減少したときに発行されるイベント。

詳細
_spender配列内の複数のアカウントが承認されたとき、または現在のチェーンとは異なる宛先チェーンで_spender配列内の複数のアカウントの許可量が減少したときに発行されなければなりません。

パラメータ

  • _owner
    • 債券トークンの所有者のアドレス。
  • _spender
    • 債券の使用を許可されるアカウントのアドレスの配列。
  • _amount
    • _owner_spenderに使用を許可する債券トークンの量の配列。
  • _destinationChainID
    • 宛先チェーンを識別するユニークなIDの配列。

crossChainApprove

function crossChainApprove(address _spender, uint256 _amount, bytes32 _destinationChainID, address _destinationContract) external returns(bool);

概要
宛先チェーンで_spenderアカウントに指定された_amountの債券保有者の債券トークンを管理する権限を与える関数。

詳細
この関数は、宛先チェーンで_spenderアカウントに指定された_amountの債券保有者の債券トークンを管理する権限を与えます。

引数

  • _spender
    • 債券保有者によって承認されるアカウントのアドレス。
  • _amount
    • 承認する債券トークンの量。
  • _destinationChainID
    • 宛先チェーンを識別するユニークなID。
  • _destinationContract
    • 宛先チェーンでやり取りするスマートコントラクトのアドレス。

戻り値

  • bool
    • 承認が成功した場合はtrue、そうでない場合はfalse

crossChainBatchApprove

function crossChainBatchApprove(address[] calldata _spender, uint256[] calldata _amount, bytes32[] calldata _destinationChainID, address[] calldata _destinationContract) external returns(bool);

概要
宛先チェーンで_spender内の複数のアカウントに_amountで指定された量の債券保有者トークンを管理する権限を与える関数。

詳細
この関数は、宛先チェーンで_spender配列内の複数のアカウントに_amount配列で指定された量の債券保有者トークンを管理する権限を与えます。

引数

  • _spender
    • 債券保有者によって承認されるアカウントのアドレスの配列。
  • _amount
    • 承認する債券トークンの量の配列。
  • _destinationChainID
    • 宛先チェーンを識別するユニークなIDの配列。
  • _destinationContract
    • 転送されたトークンをDepositまたはMintするために、宛先チェーンでやり取りするスマートコントラクトの配列。

戻り値

  • bool
    • 承認が成功した場合はtrue、そうでない場合はfalse

crossChainDecreaseAllowance

function crossChainDecreaseAllowance(address _spender, uint256 _amount, bytes32 _destinationChainID, address _destinationContract) external returns(bool);

概要
宛先チェーンで_spenderの許可量を指定された_amountだけ減らす関数。

詳細
この関数は、宛先チェーンで_spenderの許可量を指定された_amountだけ減らします。

引数

  • _spender
    • 債券保有者によって承認されるアドレス。
  • _amount
    • 許可量から減らす債券トークンの量。
  • _destinationChainID
    • 宛先チェーンを識別するユニークなID。
  • _destinationContract
    • 転送されたトークンをDepositまたはMintするために、宛先チェーンでやり取りするスマートコントラクト。

戻り値

  • bool
    • 許可量の減少が成功した場合はtrue、そうでない場合はfalse

crossChainBatchDecreaseAllowance

function crossChainBatchDecreaseAllowance(address[] calldata _spender, uint256[] calldata _amount, bytes32[] calldata _destinationChainID, address[] calldata _destinationContract) external returns(bool);

概要
宛先チェーンで_spender内の複数のアカウントの許可量を_amount配列で指定された対応する量だけ減らす関数。

詳細
この関数は、宛先チェーンで_spender配列内の複数のアカウントの許可量を_amount配列で指定された対応する量だけ減らします。

引数

  • _spender
    • 債券保有者によって承認されるアカウントのアドレスの配列。
  • _amount
    • 許可量から減らす債券トークンの量の配列。
  • _destinationChainID
    • 宛先チェーンを識別するユニークなIDの配列。
  • _destinationContract
    • 転送されたトークンをDepositまたはMintするために、宛先チェーンでやり取りするスマートコントラクトの配列。

戻り値

  • bool
    • 許可量の減少が成功した場合はtrue、そうでない場合はfalse

crossChainTransfer

function crossChainTransfer(address _to, uint256 _amount, bytes calldata _data, bytes32 _destinationChainID, address _destinationContract) external returns(bool);

概要
現在のチェーンから別のチェーンに_amountの債券トークンを_toアドレスに移動する(例:イーサリアムからポリゴンにトークンを移動する)関数。

詳細
この関数は、現在のチェーンから別のチェーンに_amountの債券トークンを_toアドレスに移動します。
また、転送されるトークンにデータを添付することもできます。

引数

  • _to
    • 債券トークンを送信するアカウントのアドレス。
  • _amount
    • 転送する債券トークンの量。
  • _data
    • 債券保有者が提供する追加情報。
  • _destinationChainID
    • 宛先チェーンを識別するユニークなID。
  • _destinationContract
    • 転送された債券トークンをDepositまたはMintするために、宛先チェーンでやり取りするスマートコントラクト。

戻り値

  • bool
    • 転送が成功した場合はtrue、そうでない場合はfalse

crossChainBatchTransfer

function crossChainBatchTransfer(address[] calldata _to, uint256[] calldata _amount, bytes[] calldata _data, bytes32[] calldata _destinationChainID, address[] calldata _destinationContract) external returns(bool);

概要
現在のチェーンから別のチェーンに、_amount配列で指定された量の複数の債券トークンを、_to配列の対応するアカウントに転送する関数。

詳細
この関数は、現在のチェーンから別のチェーンに、_amount配列で指定された量の複数の債券トークンを、_to配列の対応するアカウントに転送します。
また、転送されるトークンにデータを添付することもできます。

引数

  • _to
    • 債券を送信するアカウントのアドレスの配列。
  • _amount
    • 転送する債券トークンの量の配列。
  • _data
    • 債券保有者が提供する追加情報の配列。
  • _destinationChainID
    • 宛先チェーンを識別するユニークなIDの配列。
  • _destinationContract
    • 転送された債券トークンをDepositまたはMintするために、宛先チェーンでやり取りするスマートコントラクトの配列。

戻り値

  • bool
    • 転送が成功した場合はtrue、そうでない場合はfalse

crossChainTransferFrom

function crossChainTransferFrom(address _from, address _to, uint256 _amount, bytes calldata _data, bytes32 _destinationChainID, address _destinationContract) external returns(bool);

概要
現在のチェーンから別のチェーンに、_fromアカウントから_toアカウントに_amountの債券トークンを転送する関数。
呼び出し元は_fromアドレスによって承認されていなければならない。

詳細
この関数は、現在のチェーンから別のチェーンに、_fromアカウントから_toアカウントに_amountの債券トークンを転送します。
呼び出し元は_fromアドレスによって承認されていなければなりません。
また、転送されるトークンにデータを添付することもできます。

引数

  • _from
    • 債券保有者のアドレス。
  • _to
    • 債券を転送するアカウントのアドレス。
  • _amount
    • 転送する債券トークンの量。
  • _data
    • トークン保有者が提供する追加情報。
  • _destinationChainID
    • 宛先チェーンを識別するユニークなID。
  • _destinationContract
    • 転送されたトークンをDepositまたはMintするために、宛先チェーンでやり取りするスマートコントラクト。

戻り値

  • bool
    • 転送が成功した場合はtrue、そうでない場合はfalse

crossChainBatchTransferFrom

function crossChainBatchTransferFrom(address[] calldata _from, address[] calldata _to, uint256[] calldata _amount, bytes[] calldata _data, bytes32[] calldata _destinationChainID, address[] calldata _destinationContract) external returns(bool);

概要
現在のチェーンから別のチェーンに、_from配列のアカウントから_to配列のアカウントに、_amount配列で指定された量の複数の債券トークンを転送する関数。
呼び出し元は、_amount配列で指定された対応する量を使用するために、_fromアカウントによって承認されていなければならない。

詳細
この関数は、現在のチェーンから別のチェーンに、_from配列のアカウントから_to配列のアカウントに、_amount配列で指定された量の複数の債券トークンを転送します。
呼び出し元は、_amount配列で指定された対応する量を使用するために、_fromアカウントによって承認されていなければなりません。
また、転送されるトークンにデータを添付することもできます。

引数

  • _from
    • 債券保有者のアドレスの配列。
  • _to
    • 債券を転送するアカウントのアドレスの配列。
  • _amount
    • 転送する債券トークンの量の配列。
  • _data
    • トークン保有者が提供する追加情報の配列。
  • _destinationChainID
    • 宛先チェーンを識別するユニークなIDの配列。
  • _destinationContract
    • 転送されたトークンをDepositまたはMintするために、宛先チェーンでやり取りするスマートコントラクトの配列。

戻り値

  • bool
    • 転送が成功した場合はtrue、そうでない場合はfalse

補足

このERC(Ethereum Request for Comments)の設計は、トークン化された債券への移行を簡素化することを目的としており、従来の債券標準との整合性を維持しています。
このアプローチにより、固定利付き金融商品をオンチェーントークンとして表現し、ウォレットを通じて管理し、分散型取引所などのアプリケーションで利用することができます。
また、他の標準に関連する複雑さと非効率性を回避することができます。
このERCは、従来の債券と同様の特性を持つ新しい債券トークンの作成を容易にし、債券の取引と管理におけるアクセシビリティ、流動性、コスト効率を向上させます。

issueVolumeprincipalOfなどの伝統的な金融用語を使用することで、従来の債券言語との整合性を維持し、従来の事業体の適応を容易にすることを目的としています。

総供給量とアカウント残高

totalSupplybalanceOfの関数は、issueVolumeprincipalOfdenominationから導出できるため、定義されていません。
ただし、これらの関数は、この標準を実装する任意のコントラクトに追加することができ、これらの値の間の適切な関係を確保することができます。

function totalSupply() external view returns(uint256) {
    return issueVolume() / denomination();
}

function balance0f(account) external view returns(uint256) {
    return principal(account) / denomination();
}

上記のコードでは、totalSupply関数はissueVolumedenominationで割ることで総供給量を計算しています。
同様に、balanceOf関数はprincipal(account)denominationで割ることで、特定のアカウントの残高を計算しています。

これらの関数は、必要に応じてコントラクトに追加することができますが、必須ではありません。
これにより、コントラクトの実装者は、必要な機能のみを含めることができ、不要な複雑さを避けることができます。

互換性

このERCは、totalSupplybalanceOfなどの特定の関数がないため、ERC20ERC1155などの既存の標準とは後方互換性がありません。
トークン化された債券の発行には、この標準の純粋な実装が推奨されます。
他の標準との混合ソリューションは失敗する可能性が高いためです。

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

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

ここでの主な理由は以下の通りです。

  • ERC20ERC1155は、主にユーティリティトークンやNFT(非代替性トークン)を扱うために設計されています。

    • 一方、このERCは、債券のような固定利付き金融商品に特化しています。
  • totalSupplybalanceOfなどの関数は、ERC20ERC1155では必須ですが、このERCでは、issueVolumeprincipalOfdenominationから導出できるため、明示的に定義されていません。

  • このERCは、債券特有の機能(クーポン、満期日、元本など)を提供しますが、これらはERC20ERC1155では直接サポートされていません。

  • 異なる標準を混在させると、セキュリティ上の問題や予期しない動作が発生する可能性があります。

    • 純粋な実装を使用することで、これらのリスクを最小限に抑えることができます。

したがって、トークン化された債券を発行する時は、このERCの純粋な実装を使用することが推奨されます。
これにより、債券の特性を適切に表現し、他の標準との互換性の問題を回避することができます。

ただし、既存のシステムとの統合が必要な場合は、適切なアダプターやラッパーを使用して、このERCと他の標準との間の変換を行うことができます。

実装

以下に参考実装コードが格納されています。

以下のオプションが組み込まれた債券は、提案されたインターフェイスを統合した以下のERC7092.solを継承することで作成できます。

CALLABLE BONDS

pragma solidity ^0.8.0;

import 'ERC7092.sol';

contract ERC7092Callable is ERC7092 {
    // WRITE THE LOGIC TO ALLOW THE ISSUER TO CALL BONDS
    // STATE VARIABLES AND FUNCTIONS NEEDED
    
    /**
    * @notice call bonds owned by `_investor`
    *         MUST be called by the issuer only
    */
    function call(address _investor) public {
        require(msg.sender == _issuer[bondISIN].issuerAddress, "ERC7092Callable: ONLY_ISSUER");
        require(_principals[_investor] > 0, "ERC7092Callable: NO_BONDS");
        require(block.timestamp < _bond[bondISIN].maturityDate, "ERC7092Callable: BOND_MATURED");
        
        uint256 principal =  _principals[_investor];
        _principals[_investor] = 0;
        
        // ADD LOGIC HERE
    }
}

このコントラクトは、ERC7092を拡張して、コール可能な債券(Callable Bonds)の機能を追加しています。
コール可能な債券とは、発行者が特定の条件下で満期前に債券を償還(コール)できる権利を持つ債券のことです。

コントラクトの主な特徴は以下の通りです。

  • ERC7092CallableERC7092を継承しており、ERC7092の全ての機能を持ちます。

  • call関数は、発行者のみが呼び出すことができます。

    • これは、msg.sender_issuer[bondISIN].issuerAddressと一致するかどうかを確認することで実現しています。
  • call関数は、指定された投資家(_investor)が保有する債券をコールします。

  • 関数内では、以下の要件が確認されます。

    • _investorが債券を保有していること(_principals[_investor] > 0)。
    • 債券が満期に達していないこと(block.timestamp < _bond[bondISIN].maturityDate)。
  • _investorの元本(principal)を取得し、_principals[_investor]をゼロに設定することで、_investorが保有する債券が消去されます。

  • // ADD LOGIC HEREのコメントがあり、ここに追加のロジックを記述する必要があります。

    • 例えば、償還金の支払いや、イベントの発行などが考えられます。

このコントラクトは、発行者に債券のコールを可能にすることで、より柔軟な債券管理を提供します。
ただし、コール可能な債券は投資家にとってはリスクが高くなる可能性があるため、適切な条件設定が重要です。

また、このコードは一部の機能しか示されていないため、実際の使用には追加の実装が必要です。
特に、_issuer_bondなどの状態変数や関数が定義されていないため、これらを適切に実装する必要があります。

PUTTABLE BONDS

pragma solidity ^0.8.0;

import 'ERC7092.sol';

contract ERC7092Puttable is ERC7092 {
    // WRITE THE LOGIC TO ALLOW INVESTORS TO PUT BONDS
    // STATE VARIABLES AND FUNCTIONS NEEDED
    
    /**
    * @notice put bonds
    *         MUST be called by investors who own bonds
    */
    function put() public {
        require(_principals[msg.sender] > 0, "ERC7092Puttable: ONLY_INVESTORS");
        require(block.timestamp < _bond[bondISIN].maturityDate, "ERC7092Puttable: BOND_MATURED");
        
        uint256 principal =  _principals[msg.sender];
        _principals[msg.sender] = 0;
        
        // ADD LOGIC
    }
}

このコントラクトは、ERC7092を拡張して、プット可能な債券(Puttable Bonds)の機能を追加しています。
プット可能な債券とは、投資家が特定の条件下で満期前に債券を発行者に売り戻す(プットする)権利を持つ債券のことです。

コントラクトの主な特徴は以下の通りです。

  • ERC7092PuttableERC7092を継承しており、ERC7092の全ての機能を持ちます。

  • put関数は、債券を保有する投資家のみが呼び出すことができます。

    • これは、_principals[msg.sender] > 0を確認することで実現しています。
  • 関数内では、以下の要件が確認されます。

    • 呼び出し元(msg.sender)が債券を保有していること(_principals[msg.sender] > 0)。
    • 債券が満期に達していないこと(block.timestamp < _bond[bondISIN].maturityDate)。
  • msg.senderの元本(principal)を取得し、_principals[msg.sender]をゼロに設定することで、msg.senderが保有する債券が消去されます。

  • // ADD LOGICのコメントがあり、ここに追加のロジックを記述する必要があります。

    • 例えば、投資家への元本の返済や、イベントの発行などが考えられます。

このコントラクトは、投資家に債券のプットを可能にすることで、より柔軟な債券投資を提供します。
これは、投資家が満期前に資金を回収する必要がある場合に役立ちます。

ただし、プット可能な債券は発行者にとってはリスクが高くなる可能性があるため、適切な条件設定が重要です。
また、発行者は、プットに応じるための十分な流動性を確保する必要があります。

このコードも、ERC7092Callableと同様に、一部の機能しか示されていないため、実際の使用には追加の実装が必要です。
特に、_principals_bondなどの状態変数や関数が定義されていないため、これらを適切に実装する必要があります。

CONVERTIBLE BONDS

pragma solidity ^0.8.0;

import 'ERC7092.sol';

contract ERC7092Convertible is ERC7092 {
    // WRITE THE LOGIC TO ALLOW INVESTOR OR ISSUER TO CONVERT BONDS TO EQUITY
    // STATE VARIABLES AND FUNCTIONS NEEDED
    
    /**
    * @notice convert bonds to equity. Here we assumed that the investors must convert their bonds to equity
    *         Issuer can also convert invetsors bonds to equity.
    */
    function convert() public {
        require(_principals[msg.sender] > 0, "ERC7092Convertible: ONLY_INVESTORS");
        require(block.timestamp < _bond[bondISIN].maturityDate, "ERC7092Convertible: BOND_MATURED");
        
        uint256 principal =  _principals[msg.sender];
        _principals[msg.sender] = 0;
        
        // ADD LOGIC HERE
    }
}

このコントラクトは、ERC7092を拡張して、転換社債(Convertible Bonds)の機能を追加しています。
転換社債とは、特定の条件下で債券を株式に転換できる権利を持つ債券のことです。

コントラクトの主な特徴は以下の通りです。

  • ERC7092ConvertibleERC7092を継承しており、ERC7092の全ての機能を持ちます。

  • convert関数は、債券を保有する投資家または発行者が呼び出すことができます。

    • ここでは、投資家が自分の債券を株式に転換しなければならないと想定しています。
  • 関数内では、以下の要件が確認されます。

    • 呼び出し元(msg.sender)が債券を保有していること(_principals[msg.sender] > 0)。
    • 債券が満期に達していないこと(block.timestamp < _bond[bondISIN].maturityDate)。
  • msg.senderの元本(principal)を取得し、_principals[msg.sender]をゼロに設定することで、msg.senderが保有する債券が消去されます。

  • // ADD LOGIC HEREのコメントがあり、ここに追加のロジックを記述する必要があります。

    • 例えば、債券を株式に転換するためのメカニズムや、イベントの発行などが考えられます。

このコントラクトは、投資家または発行者に債券の株式への転換を可能にすることで、より柔軟な資金調達と投資の選択肢を提供します。
転換社債は、株式の潜在的な上昇を享受しながら、債券の安全性も持つ独特な金融商品です。

ただし、転換社債の実装には、転換率、転換期間、転換条件など、多くの詳細な設定が必要です。
また、株式トークンとのインタラクションも必要になるため、より複雑なコントラクト設計が求められます。

このコードも、前の例と同様に、一部の機能しか示されていないため、実際の使用には追加の実装が必要です。
特に、_principals_bondなどの状態変数や関数が定義されていないため、これらを適切に実装する必要があります。
また、株式トークンとのインタラクションのための関数やインターフェースも必要になるでしょう。

アイデンティティ登録

この標準は、債券のトークン化に特化して設計されています。
この標準自体は、債券保有者の身元に関する情報を管理するものではありません。
しかし、規制要件への準拠を強化し、透明性を向上させるために、この標準の上に身元登録システムを追加し、認可された全ての投資家の身元を保存することができます。

身元登録システムを維持することで、発行者は、ERC7092標準の下で発行された債券トークンが、登録され認可されたエンティティにのみ転送されることを確保できます。
この方法は、規制遵守措置に準拠しており、債券保有者の身元を管理・検証するための構造化された方法を提供します。
また、債券トークンの不正な転送や規制に準拠しない転送を防ぐことにも役立ちます。

身元登録システムの主な特徴と利点は以下の通りです。

  • 規制遵守

    • 多くの法域では、金融商品の発行と取引に関して、投資家の身元確認(KYC:Know Your Customer)と不正防止(AML:Anti-Money Laundering)の手続きを要求しています。
    • 身元登録システムは、これらの要件を満たすために役立ちます。
  • 投資家の管理

    • 身元登録システムを使用することで、発行者は投資家の身元情報を一元的に管理できます。
    • これにより、投資家とのコミュニケーションや、配当・利息の支払いなどの処理がスムーズになります。
  • 不正転送の防止

    • 身元登録システムにより、債券トークンが認可された投資家のみに転送されることを確保できます。
    • これにより、不正な転送や、規制に準拠しない投資家への転送を防ぐことができます。
  • 透明性の向上

    • 身元登録システムは、債券保有者の身元情報を透明な方法で管理します。
    • これにより、規制当局や監査人は、必要に応じて債券保有者の身元情報を確認できます。

身元登録システムは、ERC7092標準とは独立したコントラクトまたはシステムとして実装できます。
これにより、ERC7092標準自体の複雑さを増すことなく、身元管理機能を追加できます。

ただし、身元情報の管理には、プライバシーとセキュリティの問題が伴います。
したがって、身元登録システムの設計と実装には、十分な注意とセキュリティ対策が必要です。
また、関連する法規制を遵守し、投資家のプライバシー権を尊重することが重要です。

セキュリティ

このERCを実装する時には、所有者の債券を管理するためにオペレーターを承認する関数と、債券の転送を許可する関数に関連するセキュリティリスクを慎重に検討する必要があります。
これらの関数の使用には、債券の所有者または承認されたアカウントのみがそれらを呼び出すことができるようにするための堅牢な検証が必要です。

オペレーターの承認

approvesetApprovalForAllのような関数は、他のアカウントに債券の管理を許可します。
これらの関数は、債券所有者のみが呼び出すことができるようにする必要があります。
そうでないと、悪意のあるアクターが不正にオペレーターとして承認され、所有者の債券を不正に管理する可能性があります。

債券の転送

transfertransferFromのような関数は、債券の転送を許可します。
transfer関数は、債券所有者のみが呼び出すことができるようにする必要があります。
一方、transferFrom関数は、債券所有者か承認されたオペレーターのみが呼び出すことができるようにする必要があります。
これらの制限がない場合、誰でも債券を不正に転送することができてしまいます。

入力検証

これらの関数への入力は、常に検証する必要があります。
例えば、転送する債券の量が、所有者または承認されたオペレーターが利用可能な量を超えていないか確認する必要があります。
また、受取人のアドレスが有効であることを確認する必要があります。
不適切な入力検証は、意図しない動作やセキュリティ脆弱性につながる可能性があります。

再入可能性

これらの関数は、再入攻撃に対して脆弱である可能性があります。
再入攻撃とは、関数が外部のコントラクトとインタラクションする際に、その外部コントラクトが悪意を持って元の関数を再び呼び出すことで、意図しない動作を引き起こすものです。
この問題を防ぐには、Checks-Effects-Interactions パターンに従うか、再入ガード修飾子を使用する必要があります。

アクセスコントロール

債券の管理に関連する重要な関数へのアクセスは、適切にコントロールする必要があります。
例えば、issue関数は、認可された発行者のみが呼び出すことができるようにする必要があります。
適切なアクセスコントロールがない場合、不正なアクターが認可されていない操作を実行する可能性があります。

これらのセキュリティ上の考慮事項は、スマートコントラクトの開発において非常に重要です。
適切な検証とアクセスコントロールを実装することで、潜在的な脆弱性を最小限に抑え、債券トークンの安全性と完全性を確保することができます。

また、スマートコントラクトのコードは、デプロイ前に徹底的に監査し、潜在的な脆弱性を特定して修正する必要があります。
定期的なセキュリティ監査とアップデートも、長期的なセキュリティを維持するために重要です。

引用

Samuel Gwlanold Edoumou (@Edoumou), "ERC-7092: Financial Bonds," Ethereum Improvement Proposals, no. 7092, May 2023. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7092.

最後に

今回は「伝統的な債券の特徴を維持しつつ、債券のトークン化を簡素化することを目的とした新しいERC標準の仕組みを提案しているEIP7092」についてまとめてきました!
いかがだったでしょうか?

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

Twitter @cardene777

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

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0