第3章 リファレンスアーキテクチャと要件定義#
本章では、手を動かす前に全体設計と要件を確定します。本書が題材とするのは、私募債(プライベート・ボンド)をトークン化するプロジェクトです。以降の章(実装・テスト)は、すべて本章で定義する要件に対応づけて進めます。
本章の要件は、各要件に R-* 形式の ID を付けて定義します。この ID は第9章のテストケース表がトレーサビリティのために参照するもので、ID の定義元は本章です。
前提の確認(第2章より再掲): オンチェーンの残高が、法的な権利の唯一の根拠になるとは限りません。トークンが表章する権利の帰属は、採用する法的ストラクチャに依存します。証券該当性を含む法的判断は、専門家に確認してください。本書は技術設計を扱うものであり、法的助言ではありません。
3.1 要件定義#
3.1.1 ロールとユースケース#
本プロジェクトの登場者(ロール)は3種類です。
| ロール | 役割 |
|---|---|
| 発行体 | トークンを発行する主体。凍結・強制回収などの統制権限を持つ |
| 投資家 | トークンを保有・移転する主体。KYC を経て許可された者に限る |
| 管理者 | 許可リスト(レジストリ)を運用する主体。投資家の状態を登録・変更する |
主なユースケースは、発行・移転・償還の3つです。
- 発行: 発行体が、KYC 済みの投資家へトークンを配布する。
- 移転: 投資家間でトークンを移転する。ただし許可済み投資家間に限る。
- 償還: 満期・利払い時に、オンチェーン記録とオフチェーン送金を対応づけて処理する(オフチェーン連携は第8章)。
以降、これらを満たすための要件を、区分ごとに ID 付きで定義します。
3.1.2 移転制限の要件#
金融資産のトークン化で中核となるのが、移転を許可済み投資家間に限定する制御です。
| 要件ID | 要件内容 |
|---|---|
| R-TRANSFER-01 | 送信者・受信者の双方が Approved のときのみ、移転が成立する |
| R-TRANSFER-02 | 送信者または受信者が未許可(Suspended / 未登録)なら、移転は失敗する |
| R-HOOK-01 | 移転時に、送信者・受信者双方の許可状態を検証する仕組みを持つ |
この検証は、Token-2022 の Transfer Hook 拡張と、許可リストを保持するレジストリの組み合わせで実現します(選定理由は 3.3、実装は第7章)。
3.1.3 凍結・凍結解除の要件#
発行体は、口座単位で移転を止められる必要があります。KYC 未完了の口座に、いきなりトークンが渡ることも防ぎます。
| 要件ID | 要件内容 |
|---|---|
| R-FREEZE-01 | 新規トークンアカウントは既定で Frozen とし、凍結解除(thaw)前は受領・移転できない |
| R-FREEZE-02 | 発行体は既存の口座を再度 freeze でき、freeze 中はその口座からの移転を止められる |
| R-THAW-01 | KYC 完了(= レジストリ登録)後に thaw して、初めて配布・移転が可能になる |
R-FREEZE-01 は、Token-2022 の Default Account State 拡張を Frozen に設定することで実現します(3.3)。「既定で凍結し、KYC を経てから解除する」という運用順序を、技術的に強制する設計です。
3.1.4 強制回収の要件#
規制対応(裁判所命令・当局の指示など)のため、発行体が投資家の同意なしにトークンを回収できる必要があります。これは最も強い権限であり、要件の書き方も厳密にします。
| 要件ID | 要件内容 |
|---|---|
| R-FORCE-01 | 発行体(Permanent Delegate 権限者)は、投資家の同意なしに強制移転・回収できる |
| R-FORCE-02 | Permanent Delegate 以外の主体は、強制移転できない(権限の限定) |
強制回収は Token-2022 の Permanent Delegate 拡張で実現します。ここで、本書の実装が採用した設計判断を要件レベルで明示します。
- 送信者側の許可検証の免除は、Permanent Delegate 経路に限定する。 強制回収の対象は Suspended にした投資家であるのが典型のため、送信者に Approved を要求すると強制回収が機能しません。そこで、移転の authority がミントの Permanent Delegate 拡張が保持する値と一致する場合に限り、送信者側の Approved 検証を免除します。
- 回収先(受信者)は Approved を必須とする。 免除は送信者側だけです。回収先は発行体の回収用トレジャリーアカウントとし、これをレジストリに Approved 登録します。
- Hook を迂回する例外経路は作らない。 強制回収も Token-2022 の転送経路であり、Transfer Hook は同様に呼ばれます。コンプライアンス保証を崩さないためです。
この判断の根拠と検証は、第7章 7.5(実装)および第9章のテスト(T-20〜T-23)に対応します。
3.1.5 権限・セキュリティ要件#
レジストリの運用権限と、攻撃に対する頑健性の要件です。
| 要件ID | 要件内容 |
|---|---|
| R-AUTH-01 | レジストリの状態変更は、管理者(has_one = admin)のみが行える |
| R-SEC-01 | 偽の許可レコード(所有者・シード不一致)は拒否される(account confusion 対策) |
| R-SEC-02 | 転送コンテキスト外からの Hook 直接呼び出しは拒否される |
| R-SEC-03 | 追加アカウントを差し替え・省略して Hook の検証を迂回できない |
R-AUTH-01 の権限保持のあり方(マルチシグ前提)は 3.5 で、R-SEC-* の対策実装は第7章・第10章で扱います。
3.1.6 要件ID一覧(トレーサビリティの起点)#
本章で定義した要件を一覧にします。この表が、第9章テストケース表のトレース元です。第9章は各テストをこの ID に対応づけ、未カバーの要件がないことを機械的に確認します。
| 要件ID | 区分 | 要件内容 | 主に対応するコンポーネント |
|---|---|---|---|
| R-TRANSFER-01 | 移転 | 双方 Approved のときのみ移転成立 | Transfer Hook + レジストリ |
| R-TRANSFER-02 | 移転 | 未許可(Suspended/未登録)なら移転失敗 | Transfer Hook + レジストリ |
| R-HOOK-01 | 移転 | 移転時に双方の許可状態を検証 | Transfer Hook |
| R-FREEZE-01 | 凍結 | 新規口座は既定 Frozen、thaw 前は受領・移転不可 | Default Account State |
| R-FREEZE-02 | 凍結 | 既存口座を再 freeze でき、freeze 中は移転停止 | Token-2022 freeze authority |
| R-THAW-01 | 凍結 | KYC 完了後に thaw して配布・移転が可能 | freeze authority + レジストリ |
| R-FORCE-01 | 強制回収 | Permanent Delegate は同意なしに強制回収できる | Permanent Delegate |
| R-FORCE-02 | 強制回収 | Permanent Delegate 以外は強制移転できない | Permanent Delegate + Hook |
| R-AUTH-01 | 権限 | 状態変更は管理者のみ | レジストリ(Config) |
| R-SEC-01 | セキュリティ | 偽の許可レコードを拒否 | Transfer Hook(PDA 検証) |
| R-SEC-02 | セキュリティ | 転送外からの Hook 直接呼び出しを拒否 | Transfer Hook(transferring 検証) |
| R-SEC-03 | セキュリティ | 追加アカウントの差し替え・省略を拒否 | Transfer Hook(追加アカウント検証) |
上表の要件は全12件です(R-TRANSFER-01/02、R-HOOK-01、R-FREEZE-01/02、R-THAW-01、R-FORCE-01/02、R-AUTH-01、R-SEC-01/02/03)。第9章のカバレッジ表と件数・ID が一致します。
3.2 全体アーキテクチャ#
システムはオンチェーンとオフチェーンに分かれます。オンチェーンは移転制限を技術的に強制する部分、オフチェーンは KYC 審査・アテステーション発行・資産データ管理など、チェーン外で行う部分です。
flowchart TB
subgraph OFF["オフチェーン"]
KYC["KYC プロバイダ<br/>(本人確認・適格性審査)"]
SASI["アテステーション発行者<br/>(SAS 等・任意)"]
API["発行体の管理用 API<br/>(登録・状態変更の実行)"]
DATA["資産データ<br/>(償還・利払いの原簿)"]
end
subgraph ON["オンチェーン"]
MINT["Token-2022 ミント<br/>(5 拡張付き)"]
HOOK["Transfer Hook<br/>プログラム"]
REG["レジストリ<br/>(許可リスト)"]
end
KYC -->|審査結果| API
API -->|register / set_status| REG
MINT -->|転送時に CPI| HOOK
HOOK -->|InvestorStatus を参照| REG
SASI -.->|将来: アテステーション参照| HOOK
DATA -.->|償還・利払いの突合| API
要点は次のとおりです。
- 移転可否を決めるのはオンチェーンです。Token-2022 ミントが移転のたびに Transfer Hook を呼び、Hook がレジストリの許可状態を参照して可否を判定します。
- 審査そのものはオフチェーンです。KYC 審査の結果を、管理者が API 経由でレジストリに反映します。チェーンは「審査済みか」の結果だけを保持します。
- 点線は将来・任意の拡張です。アテステーション参照(SAS)は本書のリファレンス実装では未実装で、設計方針のみを示します(3.4、第7章 7.4)。
3.3 Token Extensions の選定#
3.3.1 なぜ標準 SPL Token ではなく Token-2022 か#
標準の SPL Token には、移転時に外部プログラムを呼ぶ仕組みがありません。したがって「移転を許可済み投資家間に限る」制御を、トークン自体の機能として組み込めません。Token-2022(Token Extensions)は Transfer Hook をはじめとする拡張を持ち、移転制限・凍結・強制回収を標準機能として実現できます。このため本書では Token-2022 を採用します。
3.3.2 採用する拡張と要件の対応#
本書のミント(scripts/create-mint.ts)が実際に付与する拡張は、次の5つです。各拡張は 3.1 の要件に対応します。
| 拡張 | 対応要件 | 採用理由 |
|---|---|---|
| Transfer Hook | R-TRANSFER-01/02, R-HOOK-01 | 移転時に外部プログラム(Hook)を呼び、許可状態を検証するため |
| Permanent Delegate | R-FORCE-01/02 | 発行体による強制回収を可能にするため |
| Default Account State | R-FREEZE-01 | 新規口座を既定 Frozen にし、KYC 前の受領を防ぐため |
| Metadata Pointer | (メタデータ設計) | メタデータの所在をミント自身に指すため(第6章) |
| Token Metadata | (メタデータ設計) | 名称・シンボル等のメタデータをミントに格納するため(第6章) |
3.3.3 非採用の拡張と、その理由#
Token-2022 には他にも多くの拡張がありますが、本プロジェクトの要件には不要、または方針に合わないため採用しません。代表例を挙げます。
- Transfer Fee(送金手数料): 私募債の移転制限が目的であり、手数料徴収は要件外です。
- Confidential Transfer(秘匿送金): 発行体・管理者が移転を監査できる必要があるため、残高・移転額を秘匿する方針とは相容れません。
- Interest-Bearing(利子付き): 利払いはオフチェーンの原簿と対応づけて処理する方針(第8章)であり、トークン残高を自動増加させる拡張は使いません。
3.3.4 設計上の最重要制約:ミント側拡張は後から追加できない#
ミント側の拡張は、ミント作成時に確定し、後から追加できません。 一方、トークンアカウント側の一部拡張は、口座の作成後に有効化できるものがあります。この2つを混同しないでください。
本章の選定を「実装より前に」確定させる理由は、まさにこの制約にあります。ミントを作ってしまうと拡張構成は変えられないため、要件から必要な拡張を洗い出し、作成前に確定しておく必要があります。拡張の初期化順序(拡張初期化 → ミント初期化)を含む実装の詳細は、第6章で扱います。
3.4 コンプライアンス設計パターンの比較#
移転制限を実現する設計には複数のパターンがあります。本節では3つを比較し、本書がどれを選ぶかを判断します。各パターンの実装は本節では扱わず、選定判断に集中します(実装は第7章。とくにパターン b の SAS は 7.4)。
| パターン | 概要 | 信頼モデル | 限界 |
|---|---|---|---|
| a. Transfer Hook + オンチェーン許可リスト | Hook が発行体運用のレジストリを参照して可否判定 | 発行体(レジストリ管理者)を信頼する | 許可状態の更新は管理者の運用に依存する |
| b. アテステーション参照(SAS 等) | KYC プロバイダ等が発行したアテステーションを Hook が検証 | アテステーション発行者を信頼する | 発行者の管理・失効の扱いが設計の要点になる |
| c. 標準 SPL + オフチェーン統制のみ | オンチェーンでは制限せず、オフチェーンの規約・監視で統制 | オフチェーン運用を信頼する | オンチェーンでは移転を技術的に止められない |
本書はパターン a を選定します。 理由は次のとおりです。
- 発行体が統制主体である私募債では、「発行体が運用するレジストリを信頼する」モデルが自然で、権限の所在が明確です。
- 移転可否をオンチェーンで技術的に強制できます(パターン c はこれができません)。
- パターン b のアテステーション参照は有力な選択肢ですが、発行者の管理・失効の設計が追加で必要になり、SAS の仕様確認も要します。本書はまず a を実装し、b は将来の拡張・併用の候補として位置づけます。
なお a と b は排他ではなく、レジストリで発行体の統制を効かせつつ、アテステーションで外部審査結果を取り込む併用も考えられます。この設計方針の詳細と、SAS の最新仕様確認の必要性は、第7章 7.4 で扱います。
3.5 鍵管理・権限設計#
本システムには、強い権限が複数あります。それぞれを誰が保持するかを設計で確定します。
| 権限 | 対象 | 保持者(実運用の想定) |
|---|---|---|
| mint authority | 新規発行 | 発行体(マルチシグ) |
| freeze authority | 口座の freeze / thaw | 発行体(マルチシグ) |
| permanent delegate | 強制回収 | 発行体(マルチシグ) |
| upgrade authority | プログラムの更新 | 発行体(マルチシグ) |
| レジストリ admin | 投資家状態の変更 | 管理者(マルチシグ) |
実運用では、これらの権限をマルチシグで保持することを前提とします。 単一の鍵にこれだけの権限が集中すると、その鍵の漏洩が全体の危殆化に直結するためです。権限のマルチシグ化・ローテーションの手順は第10章で扱います。
テストとの書き分け: 本書の統合テスト(第9章)では、簡略化のため単一の
payerが上記の権限を兼務します。これはテストを読みやすくするための構成であり、実運用の推奨ではありません。実運用では権限を分離し、マルチシグ化してください。
3.6 アカウント(PDA)設計#
レジストリの状態は、2種類の PDA(Program Derived Address)に格納します。実装(programs/registry/src/state.rs / constants.rs)の定義に対応します。
- Config PDA — レジストリ全体の設定。シード
["config"]から導出される単一の PDA。 - InvestorStatus PDA — 投資家1名分の許可状態。シード
["investor", investor_pubkey]から導出。
加えて、Transfer Hook は追加アカウントの定義を格納する ExtraAccountMetaList PDA(ミントごと)を持ちます(第7章)。
各 PDA のフィールドは次のとおりです。
classDiagram
class Config {
+Pubkey admin
+u8 bump
seeds = ["config"]
}
class InvestorStatus {
+Pubkey investor
+InvestorState state
+u8 bump
seeds = ["investor", investor_pubkey]
}
class InvestorState {
<<enumeration>>
Approved
Suspended
}
InvestorStatus --> InvestorState : state
設計上の要点は次のとおりです。
- Config は単一インスタンスです。シードに可変要素がないため、ワークスペースに1つだけ存在します。
adminが状態変更の唯一の権限者です(R-AUTH-01)。 - InvestorStatus は投資家ごとに1つです。シードに投資家のアドレスを含むため、投資家1名につき1つの PDA が決まります。
stateが Approved / Suspended を保持します。 - 許可状態は Approved / Suspended の2値です。KYC 失効・凍結などで移転を認めない状態を Suspended で表します。
Hook が許可レコードを検証する際は、この PDA の所有者がレジストリであることと、シードが正しいことを確認します。これにより、偽のレコードや他人のレコードの流用を拒否します(R-SEC-01。実装は第7章 7.3)。
3.7 KYC からの全体フロー(概要)#
投資家がトークンを保有できるようになるまでの流れを、全体像として示します。登場者と大まかな順序を確認することが目的です。プロバイダ連携・API・thaw 操作を含む実装レベルの詳細シーケンスは、第8章 8.2(オフチェーン連携)で扱います。
大まかな流れは次のとおりです。
- KYC 審査(オフチェーン): KYC プロバイダが投資家の本人確認・適格性を審査する。
- レジストリ登録: 審査を通過した投資家を、管理者が Approved でレジストリに登録する(R-THAW-01 の前提)。
- 口座の凍結解除(thaw): 発行体が投資家のトークンアカウントを thaw する。新規口座は既定 Frozen のため、この操作で初めて受領可能になる(R-FREEZE-01 / R-THAW-01)。
- 配布・移転: 発行体が発行し、以降は許可済み投資家間で移転できる(R-TRANSFER-01)。
- 状態変更・強制回収(必要時): 適格性を失った投資家を Suspended にし、必要に応じて強制回収する(R-FREEZE-02 / R-FORCE-01)。
各ステップの具体的な API 呼び出し・プロバイダ連携・詳細なシーケンス図は、第8章 8.2.2 を参照してください。 本章は要件とアーキテクチャの確定に留めます。
3.8 本章の自己チェック表#
| 観点 | 結果 |
|---|---|
| スタイル規則違反 | なし(です・ます調、一文概ね80字以内、相互参照は番号、図は Mermaid、価格・投資リターン・マーケティング語彙・法的判断示唆なし。冒頭に法的権利に関する注意を明記) |
[要検証] の残数 |
0件(要件・設計は実装済みリポジトリと本章内で定義。SAS は「未実装・選定のみ」と明記し断定を避けたためタグ不要) |
| バージョン表との不一致 | なし(本章はバージョン依存の具体コマンドを含まない。拡張・仕様の帰属は一次情報で確認。本文中に「latest」「最新版」の記載なし) |
| R-* 整合(対 第9章) | 一致。本章 3.1.6 で全12件(R-TRANSFER-01/02, R-HOOK-01, R-FREEZE-01/02, R-THAW-01, R-FORCE-01/02, R-AUTH-01, R-SEC-01/02/03)を定義。ID・内容が docs/test-cases-ch9.md のトレース元と一致 |
| 実装との一致 | PDA 設計(3.6)は state.rs/constants.rs、拡張選定(3.3)は create-mint.ts の5拡張、強制回収要件(3.1.4)は transfer_hook/src/lib.rs の免除ロジックと一致(構想でなく実装の記述) |
| 章間の役割分担 | パターン比較(3.4)は選定判断のみ・実装は第7章 7.4 へ誘導。KYC フロー(3.7)は全体像のみ・詳細シーケンスは第8章 8.2 へ誘導(シーケンス図本体は第8章 8.2.2) |