# [ERC3475] 債券をトークン化して発行や償還ができる仕組みを理解しよう！

> このEIPは、ブロックチェーン上で債券をトークン化するための提案です。従来のトークン規格では、複数の償還データを持つ債券を作成することが難しかったのですが、このEIPによってその問題が解決されます。

- URL: https://cardene.dev/articles/6b45573b83b926381ac3
- 公開日: 2023-08-25
- 更新日: 2023-08-25
- トピック: Blockchain
- タグ: ethereum, solidity, ブロックチェーン, nft

## はじめに

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

https://cryptogames.co.jp/

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

https://cryptospells.jp/

今回は、債券をトークン化して、債券の発行や償還などを効率的の処理できる提案である**ERC3475**についてまとめていきます！

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

https://eips.ethereum.org/EIPS/eip-3475

## 概要

このEIPは、ブロックチェーン上で債券をトークン化するための提案です。
従来のトークン規格では、複数の償還データを持つ債券を作成することが難しかったのですが、このEIPによってその問題が解決されます。

:::message
償還データとは、債券や証券などの金融商品において、投資家が元本や利息などを受け取るための条件やタイミングを示す情報のことを指します。
債券を発行する際、投資家がいくつかの期間にわたって元本を返還されるか、または利息を受け取るか、あるいはその両方が含まれる場合があります。
これらの条件は償還データとして知られ、債券保有者が将来の収益を予測し、投資判断を行うための重要な情報です。

例えば、特定の日付に利息を支払うタイプの債券では、その利息の支払日や支払額、または元本の一部を返還するタイプの債券では、元本の償還日や金額が償還データとなります。
これらのデータは投資家や市場参加者にとって、債券の価値評価や取引戦略を検討する際に重要な要素となります。
:::

具体的には、各債券の種類を識別するためのクラスIDが導入され、それぞれのクラスには債券の発行条件やその他のデータを表すための「**ノンス**」と呼ばれる数字が関連付けられます。
このノンスは、`uint256`という特殊な形式の数値で表されます。
そして、各債券の**ノンス**は、その債券に関する情報や条件を持つことができます。
例えば、債券のメタデータ、供給量（発行数）、償還条件などが含まれます。

この新しい方法によって作成された債券は、発行や償還の条件を効率的にまとめて処理することができます。
これにより、ガスコスト（トランザクション手数料）の削減やユーザーエクスペリエンスの向上が期待されます。
最終的に、この新しい規格から生まれる債券は、二次市場で分割したり交換したりすることができるようになります。

## 動機

現在のLP（Liquidity Provider）トークンは、簡単な**EIP20**トークンで、複雑なデータ構造を持っていません。
しかし、より複雑な報酬や償還（返済）の仕組みをブロックチェーン上で管理するためには、新しいトークン規格が必要です。

新しい規格では、以下の特徴が備わっています。

#### 1. 複数のトークンIDをサポート
これにより、異なる種類のトークンを同じ枠組みで取り扱うことができます。
例えば、異なる種類の債務を異なるトークンとして発行できます。

#### 2. オンチェーンのメタデータ
トークンに関連する情報や条件をオンチェーンで保存できます。
これにより、トークンに関する詳細な情報をブロックチェーン上で管理できます。

#### 3. 柔軟なストレージパターン
従来のトークン規格では、特定のデータ構造が必要でしたが、新しい規格では柔軟なデータの保存が可能です。

#### 4. ガス効率が良い
トランザクションの手数料（ガス）を削減するために、効率的な方法でデータを管理します。

また、この新しい規格には以下の利点もあります。

- このEIPによって、同じ方法で異なる種類の債務を作成できるようになります。
    - これにより、複雑なトークンの作成が容易になります。
- 第三者のウォレットアプリケーションや取引所も、この規格に準拠したトークンの情報を簡単に読み取ることができます。
    - これにより、トークンの管理や取引がスムーズに行えます。
- 作成された債券は、トレード可能なユニットとしてまとめて扱うことができます。
    - そして、これらのユニットは二次市場で分割や交換が可能です。

この新しい規格は、複雑な金融商品の管理や取引をより効率的に行うための手段として提供されています。

## 仕様

### 定義

**Bunk**

Bunkとは、特定の条件を満たすために必要なお金や資金を手に入れた後、債券を作成したり、元本を返済したり、債券を取り消したりする機関のことを指します。
一般的には、この役割を担うのは管理アクセスを持つ単一の組織やエンティティです。
この組織は、債券の発行や償還、取り消しといったトランザクションを管理し、債券が正しく運用されることを確保します。
そのため、銀行は債券に関するプール（集積）への管理権限を持っています。

### 関数

```javascript
pragma solidity ^0.8.0;

function transferFrom(address _from, address _to, Transaction[] calldata _transactions) external;

function transferAllowanceFrom(address _from,address _to, Transaction[] calldata _transactions) public ;

function issue(address _to, Transaction[] calldata _transaction) external; 

function redeem(address _from, Transaction[] calldata _transactions) external; 

function burn(address _from, Transaction[] calldata _transactions) external; 

function approve(address _spender, Transaction[] calldata _transactions) external;

function setApprovalFor(address _operator, bool _approved) external returns(bool approved);

function totalSupply(uint256 classId, uint256 nonceId) external view returns (uint256);

function redeemedSupply(uint256 classId, uint256 nonceId) external view returns (uint256);

function activeSupply(uint256 classId, uint256 nonceId) external view returns (uint256);

function burnedSupply(uint256 classId, uint256 nonceId) external view returns (uint256);

function balanceOf(address _account, uint256 classId, uint256 nonceId) external view returns (uint256);

function classMetadata(uint256 metadataId) external view returns (Metadata memory);

function nonceMetadata(uint256 classId, uint256 metadataId) external view returns (Metadata memory);

function classValues(uint256 classId, uint256 metadataId) external view returns (Values memory);

function nonceValues(uint256 classId, uint256 nonceId, uint256 metadataId) external view returns (Values memory);

function getProgress(uint256 classId, uint256 nonceId) external view returns (uint256 progressAchieved, uint256 progressRemaining);

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

function isApprovedFor(address _owner, address _operator) external view returns (bool);
```

#### transferFrom

**概要**
トークンの送付を行う関数。

**詳細**
指定したアドレスから別のアドレスへトークンを送付します。
複数のトランザクションが同時に行われることもあります。
送信元アドレスから送信先アドレスに、指定した債券クラスID、ノンスID、数量のトークンを送信します。

**引数**
- `_from`
    - トークンの送信元アドレス。
- `_to`
    - トークンの送信先アドレス。
- `_transactions`
    - トランザクションの配列。
    - 各トランザクションは債券クラスID、ノンスID、数量を持つ。

---

#### transferAllowanceFrom

**概要**
特定の承認範囲内でトークンの送付を行う関数。

**詳細**
承認されたトークンの範囲内で、指定したアドレスから別のアドレスへトークンを送信します。
複数のトランザクションが同時に行われることもあります。
送信元アドレスから送信先アドレスに、指定した債券クラスID、ノンスID、数量のトークンを送信します。

**引数**
- `_from`
    - トークンの送信元アドレス。
- `_to`
    - トークンの送信先アドレス。
- `_transactions`
    - トランザクションの配列。
    - 各トランザクションは債券クラスID、ノンスID、数量を持つ。

---

#### issue

**概要**
指定したアドレスにトークンを発行する関数。

**詳細**
特定のアドレスに、指定した債券クラスID、ノンスID、数量のトークンを発行します。
発行は特定のエンティティによって行われる必要があります。
複数のトランザクションが同時に行われることもあります。

**引数**
- `_to`
    - トークンを発行するアドレス。
- `_transactions`
    - トランザクションの配列。
    - 各トランザクションは債券クラスID、ノンスID、数量を持つ。
---

#### redeem

**概要**
トークンの償還を許可する関数。

**詳細**
指定したアドレスからトークンを償還します。
償還は特定の条件を満たした後に行われる必要があります。
償還はBunkや二次市場メーカーコントラクトによってのみ行われるべきです。

**引数**
- `_from`
    - トークンの償還元アドレス。
- `_transactions`
    - トランザクションの配列。
    - 各トランザクションは債券クラスID、ノンスID、数量を持つ。

---

#### burn

**概要**
トークンをバーン（0アドレスに送付）する関数。

**詳細**
指定したアドレスからトークンをバーンします。
バーンは特定の条件を満たした後に行われる必要があります。
バーンはBunkや二次市場メーカーコントラクトによってのみ行われるべきです。

**引数**
- `_from`
    - トークンのバーン元アドレス。
- `_transactions`
    - トランザクションの配列。
    - 各トランザクションは債券クラスID、ノンスID、数量を持つ。

---

#### approve

**概要**
特定のアドレスに対するトークンの承認をする関数。

**詳細**
指定したアドレスに対して、特定の債券クラスID、ノンスID、数量のトークンを承認します。
承認はBunkやアカウントの所有者によってのみ行われます。

**引数**
- `_spender`
    - トークンを送信することを許可するアドレス。
- `_transactions`
    - トランザクションの配列。
    - 各トランザクションは債券クラスID、ノンスID、数量を持つ。

---

#### setApprovalFor

**概要**
第三者（**オペレータ**）が所有者の特定の債券クラスを管理するための承認を有効または無効にする関数。

**詳細**
指定したアドレスが特定の債券クラスを管理するための承認を有効または無効にします。
承認の条件は内部関数によって定義される必要があり、Bunkやアカウントの所有者によってのみ呼び出すことができます。

**引数**
- `_operator`
    - 承認するオペレータのアドレス。
- `_approved`
    - 承認を有効にする場合は`true`、無効にする場合は`false`。

**戻り値**
承認が成功したかどうか（`true` または `false`）。

---

#### totalSupply

**概要**
指定した債券クラスとノンスのトークンの総供給量を返す関数。

**詳細**
指定した債券クラスとノンスのトークンの総供給量を返します。
この総供給量には、償還済みや無効化されたトークンも含まれます。

**引数**
- `classId`
    - 債券クラスのID。
- `nonceId`
    - ノンスのID。

**戻り値**
トークンの総供給量。

---

#### redeemedSupply

**概要**
指定した債券クラスとノンスのトークンの償還済み供給量を返す関数。

**引数**
- `classId`
    - 債券クラスのID。
- `nonceId`
    - ノンスのID。

**戻り値**
トークンの償還済み供給量。

---

#### activeSupply

**概要**
指定した債券クラスとノンスのアクティブな供給量を返す関数。

**詳細**
指定した債券クラスとノンスのアクティブな供給量を返します。
アクティブな供給量は償還済みや無効化されていないトークンの供給量です。

**引数**
- `classId`
    - 債券クラスのID。
- `nonceId`
    - ノンスのID。

**戻り値**
アクティブなトークンの供給量。

---

#### burnedSupply

**概要**
指定した債券クラスとノンスの無効化済みトークンの供給量を返す関数。

**引数**
- `classId`
    - 債券クラスのID。
- `nonceId`
    - ノンスのID。

**戻り値**
無効化済みトークンの供給量。

---

#### balanceOf

**概要**
指定したアドレスが保持する特定の債券クラスとノンスのトークン残高を返す関数。

**詳細**
指定したアドレスが保持する特定の債券クラスとノンスのトークン残高を返します。
これには償還済みのトークンも含まれます。

**引数**
- `_account`
    - トークンの残高を取得するアドレス。
- `classId`
    - 債券クラスのID。
- `nonceId`
    - ノンスのID。

**戻り値**
指定したアドレスが保持するトークンの残高。

---

#### classMetadata

**概要**
指定した債券クラスのメタデータを返す関数。

**詳細**
指定した債券クラスのメタデータを返します。
メタデータはJSON形式で提供され、タイトルやタイプ、説明などが含まれます。

**引数**
- `metadataId`
    - メタデータのインデックスID。

**戻り値**
指定した債券クラスのメタデータ（JSON形式）。

---

#### nonceMetadata

**概要**
指定した債券クラスとノンスのメタデータを返す関数。

**詳細**
指定した債券クラスとノンスのメタデータを返します。
メタデータはJSON形式で提供され、タイトルやタイプ、説明などが含まれます。

**引数**
- `classId`
    - 債券クラスのID。
- `nonceId
    - ノンスのID。
- `metadataId`
    - メタデータのインデックスID。

**戻り値**
指定した債券クラスとノンスのメタデータ（JSON形式）。

---

#### classValues

**概要**
特定の債券クラスの値を返す関数。

**詳細**
特定の債券クラスの値を返します。
これには文字列や数値、アドレスなどのデータが含まれます。

**引数**
- `classId`
    - 債券クラスのID。
- `metadataId`
    - メタデータのインデックスID。

**戻り値**
指定した債券クラスの値。

---

#### nonceValues

**概要**
特定の債券クラスとノンスの値を返す関数。

**詳細**
特定の債券クラスとノンスの値を返します。
これには文字列や数値、アドレスなどのデータが含まれます。

**引数**
- `classId`
    - 債券クラスのID。
- `nonceId`ノンスのID。
- `metadataId`メタデータのインデックスID。

**戻り値**
指定した債券クラスとノンスの値。

---

#### getProgress

**概要**
トークンの償還進行状況を取得する関数。

**詳細**
指定した債券クラスとノンスのトークンの償還進行状況を取得します。
進行状況は、償還条件に基づく進捗と残りのトークン供給量を示します。

**引数**
- `classId`
    - 債券クラスのID。
- `nonceId`
    - ノンスのID。

**戻り値**
トークンの償還進行状況。

---

#### allowance

**概要**
指定したオーナーアドレスが、特定の債券クラスとノンスに関して、指定したスペンダーアドレスがどれだけのトークンを引き出すことができるかを許可する関数。

**詳細**
オーナーアドレスとスペンダーアドレス、債券クラスID、およびノンスIDを指定して呼び出します。
この関数の呼び出しによって設定されたトークンの許可量は、`_amount`として戻り値として返されます。

**引数**
- `_owner`
    - トークンのオーナーとなるアドレス。
- `_spender`
    - トークンを引き出すことを許可されるアドレス。
- `classId`
    - 債券クラスのID。
- `nonceId`
    - ノンスのID。

**戻り値**
スペンダーアドレスがまだオーナーアドレスから引き出すことができる残高（`_amount`）。

---

#### isApprovedFor

**概要**
指定したオペレーターアドレスが、特定のオーナーアドレスの債券クラスを管理するために承認されているか取得する関数。

**詳細**
この関数は、指定したオペレーターアドレスが指定したオーナーアドレスの債券クラスを管理するために承認されているかどうかを確認します。
オーナーアドレスとオペレーターアドレスを指定して呼び出します。
もしもオペレーターアドレスが承認されている場合、`true`を、承認されていない場合、`false`を返します。

**引数**
- `_owner`
    - オーナーのアドレス。
- `_operator`
    - 承認のステータスを確認するオペレーターのアドレス。

**戻り値**
オペレーターアドレスが特定のオーナーアドレスの債券クラスを管理するために承認されている場合、`true`、
承認されていない場合、`false`を返す。

---

### イベント

```javascript
event Issue(address indexed _operator, address indexed _to, Transaction[] _transactions); 

event Redeem(address indexed _operator, address indexed _from, Transaction[] _transactions);

event burn(address _operator, address _owner, Transaction[] _transactions);

event Transfer(address indexed _operator, address indexed _from, address indexed _to, Transaction[] _transactions);

event ApprovalFor(address indexed _owner, address indexed _operator, bool _approved);
```

#### Issue

**概要**
債券が発行された時に発行されるイベント。

**詳細**
このイベントは、オペレーター（銀行アドレスなど）コントラクトが特定のエンティティに対して債券を発行する際に発行されます。

**パラメータ**
- `_operator`
    - イベントをトリガーしたオペレーターアドレス
- `_to`
    - 債券を発行する受取人のアドレス。
- `_transactions`
    - 発行するトランザクションの配列。

---

#### Redeem

**概要**
債券が償還された時に発行されるイベント。

**パラメータ**
- `_operator`
    - イベントをトリガーしたオペレーターアドレス。
- `_from`
    - 債券を償還する元のアドレス。
- `_transactions`
    - 償還するトランザクションの配列。

---

#### Burn

**概要**
債券が破棄（燃やされる）された時に発行されるイベント。

**パラメータ**
- `_operator`
    - イベントをトリガーしたオペレーターアドレス。
- `_owner`
    - 債券を破棄するアドレス。
- `_transactions`
    - 破棄するトランザクションの配列。

---

#### Transfer

**概要**
債券がアドレス間で移動された時に発行されるイベント。

**詳細**
このイベントは、オペレーターアドレスからオーナーアドレス（`_from`）から受け取るアドレス（`_to`）へ債券が移動された際に発行されます。

**引数**
- `_operator`
    - イベントをトリガーしたオペレーターアドレス。
- `_from`
    - 債券を移動する元のアドレス。
- `_to`
    - 債券を移動する先のアドレス。
- `_transactions`
    - 移動する債券のトランザクションの配列。

---

#### ApprovalFor

**概要**
債券保有者がオペレーターを承認する時に発行されるイベント。

**詳細**
このイベントは、オーナーアドレスが特定のオペレーターアドレスを債券の移動に承認する際に発行されます。

**パラメータ**
- `_owner`
    - 承認するオーナーアドレス。
- `_operator`
    - 承認されるオペレーターアドレス。
- `_approved`
    - 承認のステータス（`true`または`false`）。

---

#### メタデータ
債券クラスまたはNonceのメタデータは、以下のタイプで表されるJSONオブジェクトの配列として格納されます。
すべてのメタデータのスキーマは[こちら](https://eips.ethereum.org/assets/eip-3475/Metadata)から参照されます。

メタデータは、`Nonce`（識別子）やクラスの追加情報を定義します。
これらの情報は、フロントエンド（ユーザーインターフェース）がでのデータ管理・理解に使用されます。

**Description metadata**
```json
[
    {
        "title": "defining the title information",
        "_type": "explaining the type of the title information added",
        "description": "little description about the information stored in  the bond",
    }
]
```

example
```json
{
    "title": "localisation",
    "_type": "string",
    "description": "jurisdiction law codes compatibility"
    "values": ["fr ", "de", "ch"]
}
```

##### Nonce
メタデータ内の情報を検索するための主要な値は「`class`」というフィールドです。
以下にそのルールを示します。

- タイトルは、メタデータの説明に基づいて区別される、英数字です。
    - ただし、特定の管轄によって異なる場合があります。
- タイトルは空にすることはできません。
- メタデータの具体例には、債券の地域化情報や管轄の詳細などがあり、これらは[`metadata.md`](https://eips.ethereum.org/assets/eip-3475/Metadata)という例の説明ファイルに記載されています。

**Nonce metadata**

```json
[	
	{	
	"title": "maturity",
	"_type": "uint",
	"description": "Lorem ipsum...",
	"values": [0, 0, 0]
	}
]
```

##### クラスメタデータ
この構造は、クラスに関する詳細情報（シンボル、リスク情報など）を定義します。
詳細な例は、クラスメタデータセクションに説明があります。

**Class metadata**

```json
[ 
	{	
	"title": "symbol",
	"_type": "string",
	"description": "Lorem ipsum...",
	"values": ["Class symbol 1", "Class symbol 2", "Class symbol 3"],
	},
	{	
	"title": "issuer",
	"_type": "string",
	"description": "Lorem ipsum...",
	"values": ["Issuer name 1", "Issuer name 2", "Issuer name 3"],
	},

	{	
	"title": "issuer_address",
	"_type": "address",
	"description": "Lorem ipsum...",
	"values":["Address 1.", "Address 2", "Address 3"]
	},

	{	
	"title": "class_type",
	"_type": "string",
	"description": "Lorem ipsum...",
	"values": ["Class Type 1", "Class Type 2", "Class Type 3"]
	},

	{	
	"title": "token_address",
	"_type": "address",
	"description": "Lorem ipsum...",
	"values":["Address 1.", "Address 2", "Address 3"]
	},

	{	
	"title": "period",
	"_type": "uint",
	"description": "Lorem ipsum...",
	"values": [0, 0, 0]
	}
]
```

##### データのデコード
対応するフロントエンドがメタデータを理解するために、`ClassMetadata`や`NonceMetadata`という関数を使用して、債券の情報を解読する必要があります。

これは、`ClassMetadata`や`NonceMetadata`という関数のインターフェースをオーバーライドして、JSONオブジェクトとして格納された情報を読み取るためのキー（インデックス）を定義することによって行われます。

例:
```json
{
 "title": "symbol",
 "_type": "string",
 "description": "以下の形式で一意の識別子名を定義します：（シンボル、債券の種類、満期までの月数）",
 "values": ["クラス名1", "クラス名2", "DBIT Fix 6M"]
}
```

上記の例では、与えられたクラスIDを使ってシンボルの値を取得するために、クラスIDをキーとして`values`からシンボル値を取得し、詳細を取得するのに利用できます。

## 補足

### メタデータ構造

通常、債券のクラスや発行情報（`Nonce`）の詳細は外部に保存されることがありますが、このシステムではそれらの詳細情報を内部の構造体に格納します。
ここでのクラスは異なる債券の種類を表し、`Nonce`は異なる発行期間を表します。
同じクラスに属する`Nonce`は同じメタデータを共有します。
一方、`Nonce`は代替不可能（Non-Fungible）です。
それぞれのNonceは異なるセットのメタデータを格納できます。
そのため、債券の所有者が変わる際には、全てのメタデータが新しい所有者に引き継がれます。

```javascript
struct Values{
    string stringValue;
    uint uintValue;
    address addressValue;
    bool boolValue;
    bytes bytesValue;
}
```

```javascript
struct Metadata {
    string title;
    string _type;
    string description;
}
```

### バッチ関数

このEIPでは、バッチ操作という機能が導入されています。
これにより、複数の異なる種類の債券とそれに関連するメタデータを、一度にまとめて新しいアドレスに移動することができます。
これらの操作は、単一のトランザクション内で即座に処理されます。
トランザクションが完了すると、新しい所有者は各債券の額面価格を請求できる権利を持ちます。
この仕組みは、債券を効率的に「**パッケージング**」することができ、特に二次市場などでの取引に非常に有用です。

`Transaction`構造体は、このバッチ操作をサポートするために使用されます。

```javascript
 struct Transaction {
 uint256 classId;
 uint256 nonceId;
 uint256 _amount;
 }
```

- `classId`
    - 債券の種類を識別するための番号。
    - 異なる種類の債券を区別するために使用されます。
- `nonceId`
    - 与えられた債券クラス内での発行条件を特定するための番号。
    - 同じクラス内でも、異なる発行条件を持つ債券を区別するのに使用されます。
- `_amount`
    - このフィールドに指定された金額の債券が移動の対象。
    - 所有者がこの金額の債券を移動することが許可されます。

これにより、一度のトランザクションで複数の債券とそれに関連する情報をまとめて移動できます。
トランザクションが完了すると、新しい所有者はこれらの債券の所有権を取得し、各債券の額面価格を請求することができます。
この仕組みは、債券を効率的に管理し、取引を簡素化するのに役立ちます。

### AMMの最適化

このEIP（イーサリアム改善提案）におけるユースケースとして、AMM（Automated Market Maker）の最適化が挙げられます。
AMMは、トークンの取引を自動化する仕組みで、初期バージョンでは異なるトークンのペアを管理するために独立したスマートコントラクトと**EIP20**LPトークンを使用します。
しかし、この方法では1つのプール内の総流動性が減少し、無駄なガス消費やスリッページが発生する可能性があります。

このEIPを使用することで、債券の種類（`Class`）と発行のタイミング（`Nonce`）に対応する流動性を持つデータ構造を作成できます。
これにより、複数のトークンペアを含む大きな流動性プールを効率的に構築できるようになります。
具体的には、債券の種類と発行タイミングを知ることで、特定のトークンペアの所有者がプール内で持つ流動性を割合として表現できます。
実際に、**EIP20**LPトークンはプールファクトリーコントラクト内の専用スマートコントラクトで定義され、1つの債券として集約され、1つのプールに統合されます。

この標準の名前「**abstract storage bond**」は、外部のストレージを必要とせずに、すべての仕様（メタデータ、値、トランザクションなど）を保存できる能力に由来しています。
これにより、効率的なプールの構築と管理が可能となります。

:::message
例えば、3つの異なる種類の債券（A、B、C）があり、それぞれ異なる発行タイミング（`Nonce`）を持っています。
各債券はそれぞれ異なるトークンペアとして取引されます。

従来のアプローチでは、債券A、B、Cそれぞれに対して個別のプールが作成され、それぞれのプールでトークンの交換が行われていました。
しかし、それぞれのプールには総流動性が分散され、効率的な取引が難しい場合があります。

しかし、このEIPの標準を使用すると、新しい方法でプールを構築できます
各債券の種類と発行タイミングに対応するデータ構造を作成し、1つの大きな流動性プールにまとめます。

具体的には、債券A、B、Cそれぞれの`Class`と`Nonce`に対応するデータ構造がプール内に存在します。
各債券の所有者は、自身が持つ債券の種類と発行タイミングを知ることで、プール内での流動性を割合として表現できます。
これにより、例えば債券Aの所有者はプール内で債券Aの流動性の割合を保持し、債券BやCにも同様に対応する所有者が流動性を保持することができます。

さらに、**EIP20**LPトークンは、各債券の種類と発行タイミングに対応する専用スマートコントラクトで定義され、1つの債券として集約されます。
つまり、債券A、B、CそれぞれのLPトークンが1つの大きなプールに統合され、トークンの交換が効率的に行えるようになります。

このアプローチにより、異なる種類の債券を効率的に1つの大きなプールで取引できるようになります。
総流動性が最適化され、取引がスムーズに行える環境が実現します。
:::

## 互換性

このEIPは後方互換性があります。
つまり、既存のスマートコントラクトやウォレットもこのEIPのインターフェースを使って、新しい機能を追加できるということです。
これは、債券の発行者や受取人にとっても適用されます。
また、クライアント側のEOAウォレットも、債券の`issue()`や`redeem()`といった関数の実行に署名できれば、この標準との互換性が確保されます。

既存の**EIP20**トークンコントラクトは、既存の機能を維持しながら、このEIPの標準インターフェースを持つ銀行コントラクトに`mint`権限を委任することで、新たに債券を発行できます。
これにより、既存のトークンを債券として扱うことができます。

さらに、債券のライフサイクル全体にわたる重要なアクション（例えば、「**Issue**」「**Redeem**」「**Transfer**」関数）については、トランザクションの情報を索引付けするためにイベントが必要です。
このEIPの仕様書内で定義されているイベントは、それぞれのアクションが実行された際に発行される必要があります。

なお、この標準のインターフェースは**EIP20**や**EIP721**、**EIP1155**とも互換性があります。
これは、既存のトークンやアセットと統合しやすくする一方で、新しい債券の概念を取り入れることも可能です。

ただし、債券の読み取りや将来のアップグレードのニーズを考慮して、別途銀行コントラクトを作成することを推奨します。
これにより、債券の管理や新機能の追加がスムーズに行えるようになります。

最後に、このEIPは受け入れ可能な担保として、**EIP20**のような代替可能なトークン、**EIP721**や**EIP1155**のような非代替可能なトークン、またはこのEIPで表現される他の債券の形式を受け入れることができます。
つまり、さまざまな種類の資産を組み合わせて債券をサポートできる柔軟性があります。

## 参考実装

以下に格納しています。

https://github.com/cardene777/base-code/tree/develop/contract/contracts/ERC3475

引用: https://eips.ethereum.org/EIPS/eip-3475

## セキュリティ考慮事項
このEIPにおいてセキュリティを確保するためのポイントを説明します。

### `setApprovalFor`関数
この関数は、指定した `_operatorAddress` にトークン操作権限を与えます。
オペレーターは債券の`transfer`、`burn`、`redeem`などのアクションを実行する権限を持ちます。
ただし、この関数を使用する時には、オペレーターに与える権限の範囲を適切に制御することが重要です。
不必要な権限を与えることなく、必要な操作のみを許可するように心がけましょう。

### 一時的な`allowance`について
オーナーが特定のアドレスに特定の債券（`classId`、`bondsId`）に対する一時的な`allowance`を提供したい場合、`approve()` 関数を使用することが推奨されています。
これにより、必要な債券に対して限定的な承認を与えることができます。
これは、セキュリティを強化し、不正なアクセスを防ぐための方法です。

### イベントの発行
トランザクションのライフサイクル中（`issue`、`redeem`、`transferFrom`関数など）、仕様セクションで指定されているイベントは、それらのトランザクションが行われた際に必ず発行される必要があります。
これにより、イベントを監視してアクションをトラッキングし、セキュリティを確保することができます。

### 互換性と銀行コントラクト
既存の**EIP20**トークンコントラクトは、このEIPのインターフェースを備えた銀行コントラクトに`mint`権限を委任することで、債券の発行が可能です。
これにより、既存のトークンとの互換性を確保しつつ、新たな機能を導入することができます。

セキュリティの観点から、権限の適切な制御とイベントの正確な発行が重要です。
これにより、ユーザーの資産やデータを保護し、システム全体の信頼性を高めることができます。

## 引用

Yu Liu (@yuliu-debond), Varun Deshpande (@dr-chain), Cedric Ngakam (@drikssy), Dhruv Malik (@dhruvmalik007), Samuel Gwlanold Edoumou (@Edoumou), Toufic Batrice (@toufic0710), "ERC-3475: Abstract Storage Bonds," Ethereum Improvement Proposals, no. 3475, April 2021. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-3475.

## 最後に

今回は「債券をトークン化して、債券の発行や償還などを効率的の処理できる提案である**ERC3475**」についてまとめてきました！
いかがだったでしょうか？

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

[Twitter @cardene777](https://twitter.com/cardene777)
