🧐

XRP LedgerのLending Protocol

2024/12/13に公開

はじめに

この記事はXLS-66dとして提案されているLending Protocolを紹介するものです。

原文

この提案はまだ確定しているものではないため、今後変更される可能性があります。

Lending Protocol

概要

分散型金融(DeFi)レンディングは、ブロックチェーンエコシステム内における変革的な力です。銀行や金融機関などの仲介者を必要としないピアツーピアの代替手段を提供することで、従来の金融サービスに革命をもたらします。その核心において、DeFiレンディングプラットフォームはユーザーがデジタル資産を直接貸借できるようにし、金融包摂、透明性、効率性を促進します。

この提案は、XRP Ledgerネイティブのレンディングプロトコルの基本的な機能を導入します。このプロトコルは、プールされた資金を利用し、利息が発生するローンの事前設定された条件で、シンプルなオンチェーンの無担保固定期間ローンを提供します。本設計は、借り手の信用力を評価するためのオフチェーンの引受と信用リスク管理に依存しています。ただし、First-Loss Capital保護スキームがローンのデフォルト時の損失の一部を吸収します。

このバージョンでは、意図的に自動化されたオンチェーン担保と清算管理の複雑なメカニズムをスキップしています。代わりに、オンチェーン信用創造のための機能と必須コンポーネントに焦点を当てています。したがって、主要な設計原則は、将来的に追加の複雑な機能の導入を可能にする柔軟性と再利用性です。

1. はじめに

1.1 概要

レンディングプロトコルは、1人以上の預金者から資産を提供するためにVaultオンチェーンオブジェクトを使用します。Loan Brokerはレンディングプロトコルと関連するVaultの管理を担当します。VaultのオーナーとLoan Brokerは同じアカウントである必要がありますが、これは将来変更される可能性があります。

この仕様は、LoanBrokerLoanという2つの新しいレジャーエントリを導入します。LoanBrokerオブジェクトは、手数料やFirst-Loss Capitalカバーなど、レンディングプロトコル固有の詳細を捕捉します。さらに、Vaultから取得した資金を追跡します。Loanオブジェクトは、Loan BrokerとBorrower間のローン契約を捕捉します。

この仕様は、以下のトランザクションを導入します。

  • LoanBrokerSet: 新しいLoanBrokerオブジェクトを作成するトランザクション
  • LoanBrokerDelete: 既存のLoanBrokerオブジェクトを削除するトランザクション
  • LoanBrokerCoverDeposit: First-Loss Capitalを預け入れるトランザクション
  • LoanBrokerCoverWithdraw: First-Loss Capitalを引き出すトランザクション
  • LoanSet: 新しいLoanオブジェクトを作成するトランザクション
  • LoanDelete: 既存のLoanオブジェクトを削除するトランザクション
  • LoanManage: 既存のLoanを管理するトランザクション
  • LoanDraw: Loan資金を引き出すトランザクション
  • LoanPay: Loanの支払いを行うトランザクション

レンディングプロトコルのフローは以下の通りです。

  1. Loan BrokerがVaultレジャーエントリを作成します
  2. Loan BrokerがLoanBrokerSetトランザクションでLoanBrokerレジャーエントリを作成します
  3. 預金者がVaultに資産を預け入れます
  4. オプションで、Loan BrokerがLoanBrokerCoverDepositトランザクションでLoanBrokerにFirst-Loss Capitalを預け入れます
  5. Loan BrokerとBorrowerがLoanSetトランザクションでLoanオブジェクトを作成します
  6. BorrowerはLoanDrawトランザクションで資金を引き出し、LoanPayで支払いを行うことができます
  7. BorrowerがLoanの支払いを怠った場合、Loan BrokerはLoanManageトランザクションを使用してLoanをデフォルトにできます
  8. Loanが満期(またはデフォルト)になると、BorrowerまたはLoan BrokerはLoanDeleteトランザクションを使用してそれを削除できます
  9. オプションで、Loan BrokerはLoanBrokerCoverWithdrawトランザクションを使用してFirst-Loss Capitalを引き出すことができます
  10. すべてのLoanオブジェクトが削除されると、Loan BrokerはLoanBrokerDeleteトランザクションでLoanBrokerオブジェクトを削除できます
  11. すべてのLoanBrokerオブジェクトが削除されると、Loan BrokerはVaultオブジェクトを削除できます

1.2 コンプライアンス機能

1.2.1 Clawback

Clawbackは、資産発行者(IOUまたはMPTのみ)が資金を回収するメカニズムです。これはVaultで実行でき、レンディングプロトコルでは実行できません。

1.2.2 Freeze

Freezeは、資産発行者(IOUまたはMPTのみ)がAccountを凍結し、そのアカウントによる該当資産の送受信をブロックする機能です。さらに、発行者はGlobal Freezeを実施でき、こは該当資産保有者全員の送受信をブロックします。単一アカウントへのFreezeとGlobal Freezeの両方において、資産は発行者に対して送信できることに注意してください。

発行者がBorrowerのアカウントをFreezeした場合、Borrowerはローンの支払いや資金の引き出しができません。Freezeされたアカウントであっても、ローンを返済する義務は免除されません。
Loan BrokerのアカウントがFreezeされた場合、Brokerはローン手数料を受け取れません。新しいローンを作成でき、既存のローンは影響を受けません。ただし、Loan BrokerはFirst-Loss Capitalの預け入れや引き出しができません。

最後に、Global Freezeでの正確な動作はまだ定義されていません。TBD

1.3 リスク管理

リスク管理は、レンディングに関連するリスクを軽減するメカニズムを含みます。投資家の資産を保護するために、オプションのFirst-Loss Capital保護スキームを導入しました。このスキームでは、Loan Brokerがローンデフォルト時の損失をカバーするために部分的に清算できる資金を預け入れる必要があります。必要なFirst-Loss Capitalの額は、Vaultに対する総債務の割合です。デフォルト時には、最低必要カバー率に基づいてFirst-Loss Capitalの一部が清算されます。清算された資本は損失の一部をカバーするためにVaultに戻されます。

1.4 金利

ローンに関連する3つの基本的な金利があります。

  • Interest Rate: 元本に基づく通常の金利。これは資金を借りるコストです。
  • Late Interest Rate: 支払い遅延に対して課される高い金利。
  • Full Payment Rate: ローン全額を早期返済する場合に課される金利。

1.5 手数料

レンディングプロトコルは、Loan Brokerが設定できる複数の手数料を課します。Loan Brokerが十分なFirst-Loss Capitalを預け入れていない場合、プロトコルは手数料を課しません。

  • Management Fee: これはLoan Brokerが設定できる手数料で、ローンの利息に対して計算されます。これはVaultの預金者に送信される利息から差し引かれます。本質的に、借り手は全利息を支払いますが、その利息が預金者に到達する前にLoan Brokerがその一部を取ります。
  • Loan Origination Fee: ローンの発行に対して支払われる手数料。
  • Loan Service Fee: 各ローン支払いに対して支払われる手数料。
  • Late Payment Fee: 遅延支払いに対して支払われる手数料。
  • Early Payment Fee: 早期支払いに対して支払われる手数料。

1.6 用語

1.6.1 用語

  • Fixed-Term Loan: 既知の終了日と定期的な支払いスケジュールを持つローンの一種。
  • Principal: 借りた元本の合計額。利息やその他の手数料を除く。
  • Interest: 資産を借りるコスト。ローンの元本に対して計算される利息。借り手は時間とともにLenderに支払います。
  • Drawdown: ローンの作成後、借り手がローン資金の一部または全部をアクセスするプロセス。
  • Default: 借り手がローンの義務を履行しないこと。例えば、支払いを遅らせること。
  • First-Loss Capital: デフォルト時にVault預金者が損失を被ることを防ぐための資金。
  • Term: 借り手がローンを返済する期間。
  • Amortization: 定期的な支払いで、利息と元本を時間とともに返済するプロセス。
  • Repayment Schedule: 借り手がローンを返済するタイミングと金額を定めた計画。
  • Grace Period: ローンの期限後、Loan Brokerがローンをデフォルトにできる期間。

1.6.2 人物

  • LoanBroker: ローンを発行するエンティティ。
  • Borrower: 資金を借りるアカウント。

1.7 システム図

+-----------------+                          +-----------------+                       +-----------------+
|    Depositor    |                          |    LoanBroker   |                       |     Borrower    |
|   AccountRoot   |                          |   AccountRoot   |                       |   AccountRoot   |
|-----------------|                          |-----------------|                       |-----------------|
| Owner Directory |                          | Owner Directory |                       | Owner Directory |
+-----------------+                          +-----------------+                       +-----------------+
      ^         |                                     |                                         |
      |       Reserve                  ____________Reserve____________                       Reserve
   Account      |                     |                               |                         |
      |         V                     V                               V                         V
+-----------------+          +-----------------+          +-----------------+          +-----------------+
|                 |          |                 |1        N|                 |1        N|                 |
|     MPToken     |          |      Vault      |--------->|   LoanBroker    |--------->|       Loan      |
|                 |          |                 |          |-----------------|          |                 |
+-----------------+          +-----------------+          | Owner Directory |          +-----------------+
         |                            ^                  +-----------------+                    ^
      Issuance                        | ___________       ____________^  |_________Link_________|
         |                            |            Account            |
         V                            ^               |               ^
+-----------------+                   |      +-----------------+      |
|      Share      |                   |      |  Pseudo-Account |      |
| MPTokenIssuance |<------Issuer------| -----|   AccountRoot   |      |
|                 |                   |_Link_|-----------------|_Link_|
+-----------------+                          | Owner Directory |
                                             +-----------------+

2. レジャーエントリ

2.1. LoanBrokerレジャーエントリ

LoanBrokerオブジェクトはレンディングプロトコルの属性を捕捉します。

2.1.1 オブジェクト識別子

LoanBrokerオブジェクトのキーは、以下の値を順番に連結したSHA512-Halfの結果です。

  • LoanBrokerスペースキー0x006C(小文字のl)
  • LoanBrokerSetトランザクションを送信するアカウント(つまりLender)のAccountID
  • トランザクションのSequence番号。トランザクションがTicketを使用した場合は、TicketSequence値を使用します。

2.1.2 フィールド

LoanBrokerオブジェクトには以下のフィールドがあります。

フィールド名 変更可能? 必須? JSONの型 内部の型 デフォルト値 説明
LedgerEntryType N/A 文字列 UINT16 TODO レジャーオブジェクトのタイプ。
LedgerIndex N/A 文字列 UINT16 N/A レジャーオブジェクトの識別子。
Flags Yes 文字列 UINT32 0 レジャーオブジェクトのフラグ。
PreviousTxnID N/A 文字列 HASH256 N/A このオブジェクトを最後に変更したトランザクションのID。
PreviousTxnLgrSeq N/A 数値 UINT32 N/A このオブジェクトを最後に変更したトランザクションが含まれるレジャーのシーケンス。
Sequence N/A 数値 UINT32 N/A このオブジェクトを作成したトランザクションのシーケンス番号。
OwnerNode N/A 数値 UINT64 N/A このオブジェクトが所有者のディレクトリで参照されるページを識別します。
VaultID No 文字列 HASH256 N/A このレンディングプロトコルインスタンスに関連するVaultオブジェクトのID。
Owner No 文字列 AccountID N/A Loan Brokerのアドレス。
Data Yes string BLOB None Loan Brokerに関する任意のメタデータ。最大256バイト
ManagementFeeRate No number UINT16 0 レンディングプロトコルが課す1/10ベースポイント単位の手数料。 有効な値は0から10000までの範囲。値1は1/10ベースポイントまたは0.001%に相当します.
OwnerCount N/A number UINT32 0 Loan Brokerが発行したアクティブなローンの数。
DebtTotal N/A number NUMBER 0 レンディングプロトコルがVaultに負う債務の総額。利息を含む。
DebtMaximum Yes number NUMBER 0 レンディングプロトコルがVaultに負うことができる最大債務。デフォルト値の0は債務の制限がないことを意味します。
CoverAvailable N/A number NUMBER 0 レンディングプロトコルに預け入れられたFirst-Loss Capitalの総額。
CoverRateMinimum No number UINT16 0 ローンデフォルトをカバーするためにFirst-Loss Capitalが必要なDebtTotalの1/10ベースポイント。有効な値は0から100000までの範囲。値1は1/10ベースポイントまたは0.001%に相当します。
CoverRateLiquidation No number UINT16 0 ローンデフォルトをカバーするためにFirst-Loss Capitalが清算される必要なDebtTotalの1/10ベースポイント。有効な値は0から100000までの範囲。値1は1/10ベースポイントまたは0.001%に相当します。

2.1.3 LoanBroker pseudo-account

レンディングプロトコルは、First-Loss Capitalを保持するために関連するVaultオブジェクトの pseudo-account を使用します。

2.1.4 所有権

レンディングプロトコルオブジェクトはledgerに保存され、LoanBrokerSetトランザクションを送信するアカウントが所有する所有者ディレクトリで追跡されます。さらに、このオブジェクトは pseudo-accountOwnerDirectoryでも追跡されます。

LoanBrokerは、LoanBrokerオブジェクトがアクティブなローンがある間に削除されることを防ぎ、将来のRPCエンドポイントのために、関連するLoanオブジェクトの追跡を必要とします。したがって、LoanBrokerには関連する所有者ディレクトリオブジェクトがあります。

DirectoryNodeオブジェクトのRootIndexは、以下の値を順番に連結したSHA512-Halfの結果です。

  • OwnerDirectoryスペースキー0x004F
  • LoanBrokerID

2.1.5 準備金

LoanBrokerオブジェクトは、作成するアカウントに対して1つの所有者準備金を必要とします。

2.1.6 会計

レンディングプロトコルは、DebtTotalフィールドで関連するVaultに対する債務を追跡します。これは、Vaultから取得した元本額と支払うべき利息を捕捉し、すべての手数料は除外します。DebtMaximumフィールドは、レンディングプロトコルが負うことができる最大債務を制御します。Lenderがローンを発行するたびに、DebtTotalはローンの元本と利息(手数料を除く)だけ増加します。DebtTotal \geq DebtMaximumの場合、一部の債務が清算されるまでLenderは新しいローンを発行できません。さらに、LenderはDebtTotalDebtMaximumを超えることになるようなローンを発行することはできません。

例1: # ローンの発行 #

** 初期状態 **

-- Vault --
AssetsTotal         = 100,000 トークン
AssetsAvailable     = 100,000 トークン
SharesTotal         = 100,000 シェア

-- レンディングプロトコル --
DebtTotal           = 0
# レンディングプロトコルが利息に対して課す手数料
ManagementFeeRate   = 0.1 (10%)


# Lenderが以下のローンを発行
-- Loan --
LoanPrincipal       = 1,000 トークン
LoanInterestRate    = 0.1 (10%)

# 簡略化
LoanInterest        = LoanPrincipal x LoanInterestRate
                    = 100 トークン

** 状態変更 **

-- Vault --
# Vaultの潜在的価値を増加
AssetsTotal     = AssetsTotal + ((LoanInterest - (LoanInterest x ManagementFeeRate)))
                = 100,000 + (100 - (100 x 0.1)) = 100,000 + 90
                = 100,090 トークン

# Vaultの利用可能資産を減少
AssetsAvailable = AssetsAvailable - LoanPrincipal
                = 100,000 - 1,000
                =  99,000 トークン

SharesTotal     = (変更なし)

-- レンディングプロトコル --
# レンディングプロトコルの債務を増加
DebtTotal   = DebtTotal + LoanPrincipal + (LoanInterest - (LoanInterest x ManagementFeeRate))
            = 0 + 1,000 + (100 - (100 x 0.1)) = 1,000 + 90
            = 1,090 トークン

---------------------------------------------------------------------------------------------------

例2: # ローンの支払い #

** 初期状態 **

-- Vault --
AssetsTotal         = 100,090 トークン
AssetsAvailable     =  99,000 トークン
SharesTotal         = 100,000 シェア

-- レンディングプロトコル --
DebtTotal           = 1,090 トークン
# レンディングプロトコルが利息に対して課す手数料
ManagementFeeRate   = 0.1 (10%)

-- Loan --
LoanPrincipal       = 1,000 トークン
LoanInterestRate    = 0.1 (10%)
# 簡略化
LoanPayments        = 2

# 簡略化
LoanInterest        = LoanPrincipal x LoanInterestRate
                    = 100 トークン


# Borrowerが単一の支払いを行う

PaymentAmount           = 550 トークン
PaymentPrincipalPortion = 500 トークン
PaymentInterestPortion  =  50 トークン


** 状態変更 **

-- Vault --
AssetsTotal     = (変更なし)

# Vaultの利用可能資産を増加
AssetsAvailable = AssetsAvailable + PaymentPrincipalPortion + (PaymentInterestPortion - (PaymentInterestPortion x ManagementFeeRate))
                = 99,000 + 500 + (50 - (50 x 0.1))
                = 99,545 トークン

SharesTotal     = (変更なし)

-- レンディングプロトコル --

# レンディングプロトコルの債務を減少
DebtTotal   = DebtTotal - PaymentPrincipalAmount - (PaymentInterestPortion - (PaymentInterestPortion x ManagementFeeRate))
            = 1,090 - 500 - (50 - (50 x 0.1))
            = 545 トークン

2.1.7 First-Loss Capital

First-Loss Capitalは、ローンデフォルト時にVault預金者が損失を被ることを防ぐための任意の機能です。First-Loss Capitalは損失の一部を吸収します。以下のパラメータがFirst-Loss Capitalを制御します。

  • CoverAvailable - レンディングプロトコルオーナーが預け入れたカバーの総額
  • CoverRateMinimum - CoverAvailableDebtTotalをカバーしなければならない割合
  • CoverRateLiquidation - ローンデフォルトをカバーするために清算される最低必要カバー(DebtTotal \times CoverRateMinimum)の最大割合

利用可能なカバーが必要最低カバーを下回った場合、2つの結果が発生します。

  • Lenderは新しいローンを発行できません
  • Lenderは手数料を受け取れません。借り手の手数料は無視され(つまり、借り手はローン支払い手数料を支払う必要がない)、管理手数料はその代わりにVaultに預け入れられます

例1: ローンデフォルト

** 初期状態 **

-- Vault --
AssetsTotal             = 100,090 トークン
AssetsAvailable         = 99,000 トークン
SharesTotal             = 100,000 トークン

-- レンディングプロトコル --
DebtTotal               = 1,090 トークン
CoverRateMinimum        = 0.1 (10%)
CoverRateLiquidation    = 0.1 (10%)
CoverAvailable          = 1,000 トークン

-- Loan --
DefaultAmount = 1,090 トークン


# First-Loss Capital清算の計算

# First-Loss Capitalスキームがカバーするデフォルト額

DefaultCovered     = min((DebtTotal x CoverRateMinimum) x CoverRateLiquidation, DefaultAmount)
                    = min((1,090 * 0.1) * 0.1, 1,090) = min(10.9, 1,090)
                    = 10.9 トークン

DefaultRemaining    = DefaultAmount - DefaultCovered
                    = 1,090 - 10.9
                    = 1,079.1 トークン

** 状態変更 **

-- Vault --
AssetsTotal     = AssetsTotal - DefaultRemaining
                = 100,090 - 1,079.1
                = 99,010.9 トークン

AssetsAvailable = AssetsAvailable + DefaultCovered
                = 99,000 + 10.9
                = 99,010.9 トークン

SharesTotal = (変更なし)

-- レンディングプロトコル --
DebtTotal       = DebtTotal - DefaultAmount
                = 1,090 - 1,090
                = 0 トークン

CoverAvailable  = CoverAvailable - DefaultCovered
                = 1,000 - 10.9
                = 989.1 トークン

2.2. Loanレジャーエントリ

Loanレジャーエントリは、オンチェーン上の様々なローン条件を捕捉します。これはBorrowerとローン発行者間の契約です。

2.2.1 オブジェクト識別子

LoanIDは以下のように計算されます。

  • 以下の値のSHA512-Halfを計算。
    • Loanスペースキー0x004C(大文字L)
    • BorrowerアカウントのAccountID
    • 関連するLoanBrokerオブジェクトのLoanBrokerID
    • **LoanSet**トランザクションのSequence番号。トランザクションがTicketを使用した場合は、TicketSequence値を使用

2.2.2 フィールド

フィールド名 変更可能? 必須? JSONタイプ 内部タイプ デフォルト値 説明
LedgerEntryType N/A 文字列 UINT16 TODO Ledgerオブジェクトタイプ
LedgerIndex N/A 文字列 UINT16 N/A Ledgerオブジェクト識別子
Flags Yes 文字列 UINT32 0 Ledgerオブジェクトフラグ
PreviousTxnID N/A 文字列 HASH256 N/A このオブジェクトを最後に変更したトランザクションのID
PreviousTxnLgrSeq N/A 数値 UINT32 N/A このオブジェクトを最後に変更したトランザクションを含むledgerのシーケンス
Sequence N/A 数値 UINT32 N/A ローンを作成したトランザクションのシーケンス番号
OwnerNode N/A 数値 UINT64 N/A このアイテムがオーナーのディレクトリで参照されているページを識別
LoanBrokerID No 文字列 HASH256 N/A このLoanインスタンスに関連するLoanBrokerのID
Borrower No 文字列 AccountID N/A 借り手アカウントのアドレス
LoanOriginationFee No 数値 NUMBER N/A ローン作成時にLoanBroker.Ownerに支払われる名目資金額
LoanServiceFee No 数値 NUMBER N/A 各ローン支払いと共にLoanBroker.Ownerに支払われる名目資金額
LatePaymentFee No 数値 NUMBER N/A 支払いが遅延した場合にLoanBroker.Ownerに支払われる名目資金額
ClosePaymentFee No 数値 NUMBER N/A 全額支払いが行われた場合にLoanBroker.Ownerに支払われる名目資金額
OveraymentFee No 数値 NUMBER N/A 過払い金に対する1/100ベーシスポイント単位の手数料。有効な値は0から100000(0~100%)です。
InterestRate No 数値 UINT16 N/A 1/10ベーシスポイント単位のローンの年換算金利
LateInterestRate No 数値 UINT16 N/A 遅延支払いに対する1/10ベーシスポイント単位の金利
CloseInterestRate No 数値 UINT16 N/A 早期返済に対する1/10ベーシスポイント単位の金利
OverpaymentInterestRate No 数値 UINT16 N/A 超過支払いに対する1/10ベーシスポイント単位の金利
StartDate No 数値 UINT32 N/A ローン開始時のリップルエポック
PaymentInterval No 数値 UINT32 N/A ローン支払い間隔の秒数
GracePeriod No 数値 UINT32 N/A 支払い期限後の秒数
PreviousPaymentDate N/A 数値 UINT32 0 前回の支払い時のリップルエポック
NextPaymentDueDate N/A 数値 UINT32 LoanSet.StartDate + LoanSet.PaymentInterval 次回の支払い期限のリップルエポック
PaymentsRemaining N/A 数値 UINT32 LoanSet.PaymentsTotal 残りの支払い回数
AssetsAvailable N/A 数値 NUMBER LoanSet.[PrincipalRequested - LoanOriginationFee] ローンで利用可能な資産額
PrincipalOutstanding No 数値 NUMBER LoanSet.PrincipalRequested 借り手が要求した元本額
2.2.2.1 フラグ

Loanオブジェクトは以下のフラグをサポートします。

フラグ名 フラグ値 変更可能? 説明
lsfLoanDefault 0x0001 No 設定されている場合、ローンがデフォルトになったことを示します。
lsfLoanImpaired 0x0002 Yes 設定されている場合、ローンが債務不履行になったことを示します。
lsfLoanOverpayment 0x0003 No 設定されている場合、ローンが超過支払いをサポートしていることを示します。

2.2.3 所有権

Loanオブジェクトはレジャーに保存され、Borrower所有者ディレクトリに追跡されます。

さらに、LoanBrokerからLoanオブジェクトの検索を容易にするため、オブジェクトはLoanBrokerオブジェクトに関連するOwnerDirectoryにも追跡されます。

2.2.4 準備金

LoanオブジェクトはBorrowerの準備金を1つ消費します。

2.2.5 債務不履行

LoanBrokerが借り手が次回の支払いを行えないことを発見した場合、債務不履行によりLoanBrokerVaultに"含み損"を登録できます。債務不履行メカニズムは次回の支払い期限をローンが債務不履行になった時間に移動し、ローンをより迅速に債務不履行にすることができます。ただし、借り手が支払いを行った場合、債務不履行の状態は自動的にクリアされます。

3. トランザクション

3.1. LoanBrokerトランザクション

このセクションではLoanBrokerレジャーエントリに関連するトランザクションを指定します。

3.1.1 LoanBrokerSet

このトランザクションは新しいLoanBrokerオブジェクトを作成するか、既存のものを更新します。

フィールド名 Required? JSONタイプ 内部タイプ デフォルト値 説明
TransactionType 文字列 UINT16 TODO トランザクションタイプ
VaultID 文字列 HASH256 N/A ローンプロトコルが流動性にアクセスするために使用するVault ID
LoanBrokerID 文字列 HASH256 N/A トランザクションが変更するLoanBroker ID
Flags 文字列 UINT32 0 ローンプロトコルのフラグ
Data 文字列 BLOB None 16進数形式の任意のメタデータ。フィールドは256バイトに制限されています。
ManagementFeeRate 数値 UINT16 0 ローンプロトコルオーナーが課金する1/10ベーシスポイントの手数料。有効な値は0から10000(0~100%)です。
DebtMaximum 数値 NUMBER 0 ローンプロトコルがVaultに負うことができる最大額。デフォルト値の0は債務の上限がないことを意味します。
CoverRateMinimum 数値 UINT16 0 First-Loss Capitalが債務をカバーするために必要な1/10ベーシスポイントの比率。有効な値は0から100000(0~100%)です。
CoverRateLiquidation 数値 UINT16 0 ローン債務不履行をカバーするためにFirst-Loss Capitalが清算される必要がある1/10ベーシスポイントの比率。有効な値は0から100000(0~100%)です。
3.1.1.1 失敗条件
  • LoanBrokerIDが指定されていない場合:

    • VaultIDで指定されたVaultオブジェクトがレジャー上に存在しない。
  • 送信者のAccountRoot.Account != Vault(VaultID).Owner

  • LoanBrokerIDが指定されている場合:

    • LoanBrokerIDで指定されたLoanBrokerオブジェクトがレジャー上に存在しない。
    • 送信者のAccountRoot.Account != LoanBroker(LoanBrokerID).Owner.
    • 送信者が固定フィールドを変更しようとしている。
  • フィールドのいずれかが無効である。

3.1.1.2 状態変更
  • LoanBrokerIDが指定されていない場合:

    • 送信者のOwnerDirectoryLoanBrokerIDを追加。
    • ローンプロトコルのVault_pseudo-account_OwnerDirectoryLoanBrokerIDを追加。
  • If LoanBrokerID is specified:

    • Update appropriate fields.
3.1.1.3 不変条件

TBD

3.1.2 LoanBrokerDelete

フィールド名 必須? JSONの型 内部の型 デフォルト値 説明
TransactionType string UINT16 TODO トランザクションタイプ.
LoanBrokerID string HASH256 N/A トランザクションが削除するLoanBrokerID.
3.1.2.1 失敗条件
  • LoanBrokerIDで指定されたLoanBrokerオブジェクトがレジャー上に存在しない。

  • 送信者のAccountRoot.Account != LoanBroker(LoanBrokerID).Owner.

  • OwnerCountが0より大きい。

  • CoverAvailableが0より大きい。

3.1.2.2 状態変更
  • 送信者のOwnerDirectoryからLoanBrokerIDを削除。
  • ローンプロトコルのVault_pseudo-account_OwnerDirectoryからLoanBrokerIDを削除。
  • LoanBrokerオブジェクトに関連するOwnerDirectoryを削除。
3.1.2.3 不変条件

TBD

3.1.3 LoanBrokerCoverDeposit

このトランザクションはLoanBrokerCoverAvailableを増加させます。

フィールド名 必須? JSONの型 内部の型 デフォルト値 説明
TransactionType 文字列 UINT16 TODO トランザクションタイプ.
LoanBrokerID 文字列 HASH256 N/A First-Loss Capitalを預けるLoanBrokerID.
Amount オブジェクト NUMBER 0 First-Loss Capitalの金額.
3.1.3.1 失敗条件
  • LoanBrokerIDで指定されたLoanBrokerオブジェクトがレジャー上に存在しない。

  • 送信者のAccountRoot.Account != LoanBroker(LoanBrokerID).Owner.

    • Vault(LoanBroker(LoanBrokerID).VaultID).AssetIOUの場合

      • 送信者のアカウントと資産のIssuerRippleStateオブジェクトにlsfLowFreezeまたはlsfHighFreezeフラグが設定されている。
      • IssuerAccountRootオブジェクトにlsfGlobalFreezeフラグが設定されている。
      • トラストラインのBalanceAmountより小さい。
  • Vault(LoanBroker(LoanBrokerID).VaultID).AssetMPTの場合

    • 送信者のAccountRootMPTokenオブジェクトにVault(LoanBroker(LoanBrokerID).VaultID).Assetが設定されている。
      • lsfMPTLockedフラグが設定されている。
      • MPTAmountAmountより小さい。
    • Vault(LoanBroker(LoanBrokerID).VaultID).AssetMPTokenIssuanceオブジェクトにlsfMPTLockedフラグが設定されている。
3.1.3.2 状態変更
  • Vault(LoanBroker(LoanBrokerID).VaultID).AssetXRPの場合

    • 擬似アカウント AccountRootBalanceフィールドをAmount増加。
    • 送信者のAccountRootBalanceフィールドをAmount減少。
  • Vault(LoanBroker(LoanBrokerID).VaultID).AssetIOUの場合

    • 擬似アカウント AccountRootIssuerAccountRootRippleStateバランスをAmount増加。
    • 送信者のAccountRootIssuerAccountRootRippleStateバランスをAmount減少。
  • Vault(LoanBroker(LoanBrokerID).VaultID).AssetMPTの場合

    • 擬似アカウント MPTokenオブジェクトのMPTAmountフィールドをAmount増加。
    • 送信者のMPTokenオブジェクトのMPTAmountフィールドをAmount減少。
  • LoanBroker.CoverAvailableAmount増加。

3.1.3.3 不変条件

TBD

3.1.4 LoanBrokerCoverWithdraw

LoanBrokerCoverWithdrawトランザクションはLoanBrokerからFirst-Loss Capitalを引き出します。

フィールド名 必須? JSONの型 内部の型 デフォルト値 説明
TransactionType 文字列 UINT16 TODO トランザクションタイプ.
LoanBrokerID 文字列 HASH256 N/A First-Loss Capitalを引き出すLoanBrokerID.
Amount オブジェクト NUMBER 0 引き出す資産の金額。
3.1.4.1 失敗条件
  • LoanBrokerIDで指定されたLoanBrokerオブジェクトがレジャー上に存在しない。

  • 送信者のAccountRoot.Account != LoanBroker(LoanBrokerID).Owner.

  • Vault(LoanBroker(LoanBrokerID).VaultID).AssetIOUの場合

    • 送信者のアカウントと資産のIssuerRippleStateオブジェクトにlsfLowFreezeまたはlsfHighFreezeフラグが設定されている。
    • IssuerAccountRootオブジェクトにlsfGlobalFreezeフラグが設定されている。
  • Vault(LoanBroker(LoanBrokerID).VaultID).AssetMPTの場合

    • 送信者のAccountRootMPTokenオブジェクトにVault(LoanBroker(LoanBrokerID).VaultID).Assetが設定されている。
      • lsfMPTLockedフラグが設定されている。
    • Vault(LoanBroker(LoanBrokerID).VaultID).AssetMPTokenIssuanceオブジェクトにlsfMPTLockedフラグが設定されている。
  • 送信者が資産を引き出そうとしているが、資産がVaultの資産と一致しない。

  • LoanBroker.CoverAvailable < Amount.

3.1.4.2 状態変更
  • Vault(LoanBroker(LoanBrokerID).VaultID).AssetXRPの場合

    • 擬似アカウント AccountRootBalanceフィールドをAmount減少。
    • 送信者のAccountRootBalanceフィールドをAmount増加。
  • Vault(LoanBroker(LoanBrokerID).VaultID).AssetIOUの場合

    • 擬似アカウント AccountRootIssuerAccountRootRippleState残高をAmount減少。
    • 送信者のAccountRootIssuerAccountRootRippleState残高をAmount増加。
  • Vault(LoanBroker(LoanBrokerID).VaultID).AssetMPTの場合

    • 擬似アカウント MPTokenオブジェクトのMPTAmountフィールドをAmount減少。
    • 送信者のMPTokenオブジェクトのMPTAmountフィールドをAmount増加。
  • LoanBroker.CoverAvailableAmount減少。

3.2. Loanトランザクション

このセクションではLoanレジャーエントリーに関連するトランザクションを指定します。

3.2.1 LoanSetトランザクション

このトランザクションは新しいLoanオブジェクトを作成します。

フィールド名 必須? JSONの型 内部の型 デフォルト値 説明
TransactionType string UINT16 TODO トランザクションタイプ.
LoanBrokerID string HASH256 N/A ローンブローカーID.
Flags string UINT32 0 ローンのフラグ.
Data string BLOB None ローンのメタデータ.
Borrower string AccountID N/A ローンの借り手のアドレス.
LoanOriginationFee number NUMBER 0 ローン作成時にローンブローカーに支払われる名目上の資金額.
LoanServiceFee number NUMBER 0 ローンの支払いごとにローンブローカーに支払われる名目上の資金額.
LatePaymentFee number NUMBER 0 ローンの支払いが遅れた場合にローンブローカーに支払われる名目上の資金額.
ClosePaymentFee number NUMBER 0 ローンの早期全額返済時にローンブローカーに支払われる名目上の資金額.
InterestRate number UINT16 0 ベーシス・ポイントで表したローンの年換算金利。
LateInterestRate number UINT16 0 ベーシスポイント単位で、支払遅延に対する金利に上乗せされるプレミアム。有効な値は0~10000です。(0-100%)
CloseInterestRate number UINT16 0 ベーシスポイント単位で、早期全額返済時に課される手数料。有効な値は0~100000です。(0-100%)
PrincipalRequested number NUMBER N/A 借り手が要求した元本額。
StartDate number UINT32 N/A リップルエポックで表されるローン開始のタイムスタンプ。
PaymentsTotal number UINT32 1 ローンの支払い回数。
PaymentInterval number UINT32 60 ローンの支払い間隔(秒)。
GracePeriod number UINT32 60 ローンの支払い期限日からデフォルトになるまでの猶予期間(秒)。
Lender object STObject N/A トランザクション上の貸し手の署名を含む内部オブジェクト。
3.2.1.1 Flags
Flag名 Flag値 説明
tfLoanOverpayment 0x0001 Vaultが超過支払いをサポートすることを示します。
3.2.1.2 Lender

トランザクションに対するLenderの署名を含む内部オブジェクトです。このオブジェクトに含まれるフィールドは以下の通りです。

フィールド名 必須? JSONの型 内部の型 デフォルト値 説明
SigningPubKey 文字列 STBlob N/A 署名の有効性を検証するために使用される公開鍵。
Signature 文字列 STBlob N/A BorrowerのSignatureを含むすべての署名フィールドに対する署名。
Signers リスト STArray N/A このトランザクションの承認を示すLoanBroker.Ownerの署名者からのトランザクション署名の配列。

最終的なトランザクションにはSignatureまたはSignersのいずれかが含まれている必要があります。

Signersフィールドが必要な場合、処理が必要な追加の署名により、マルチ署名の追加手数料と同様にトランザクションの合計手数料が増加します。最小手数料は(|signatures| + 1) \times base\_feeとなります。

署名に対する合計手数料の計算は(1 + |tx.Signers| + |tx.Lender.Signers|) \times base\_feeとなります。

このフィールドは署名フィールドではありません(トランザクション署名には含まれませんが、SignatureまたはSignersフィールドは保存されたトランザクションに含まれます)。

3.2.1.3 マルチシグ

LoanSetトランザクションは、ローンを作成するためのBorrowerLoanBroke.Owner間の相互合意です。そのため、LoanSetトランザクションは両当事者によって署名される必要があります。マルチシグのフローは以下の通りです。

  1. Borrowerが事前に合意されたローン条件で新しいトランザクションを作成し、署名します。
  2. LenderBorrowerの署名を含むすべての署名フィールドに署名します。
3.2.1.4 失敗条件
  • 指定されたLoanBrokerIDを持つLoanBrokerオブジェクトがレジャー上に存在しない。

  • 送信者のAccountRoot.Account != LoanBroker(LoanBrokerID).Owner

  • Lender.Signatureが無効。

  • Vault(LoanBroker(LoanBrokerID).VaultID).AssetIOUの場合

    • 送信者アカウントと資産のIssuer間のtrustlineがfreezeされている。
    • IssuerAccountRootオブジェクトにlsfGlobalFreezeフラグが設定されている。
  • Vault(LoanBroker(LoanBrokerID).VaultID).AssetMPTの場合

    • 送信者のAccountRootVault(LoanBroker(LoanBrokerID).VaultID).Assetに対するMPTokenオブジェクト
      • lsfMPTLockedフラグが設定されている。
    • Vault(LoanBroker(LoanBrokerID).VaultID).AssetMPTokenIssuanceオブジェクトにlsfMPTLockedフラグが設定されている。
  • tfDefaulttfImpairtfUnimpairフラグのいずれかが設定されている。

  • BorrowerAccountRootオブジェクトが存在しない。

  • PaymentIntervalが60秒未満。

  • GracePeriodPaymentIntervalより大きい。

  • Loan.StartDate < CurrentTime

  • Vault内の資産が不足

    • Vault(LoanBroker(LoanBrokerID).VaultID).AssetsAvailable < Loan.PrincipalRequested
  • LoanBrokerの最大債務を超過

    • LoanBroker(LoanBrokerID).DebtMaximum < LoanBroker(LoanBrokerID).DebtTotal + Loan.PrincipalRequested
  • First-Loss Capitalが不足

    • LoanBroker(LoanBrokerID).CoverAvailable < (LoanBroker(LoanBrokerID).DebtTotal + Loan.PrincipalRequested) x LoanBroker(LoanBrokerID).CoverRateMinimum
3.2.1.5 状態変更
  • ローン資産がIOUの場合

    • IssuerBorrower間にTrustlineが存在しない場合は作成。
  • ローン資産がMPTの場合

    • BorrowerMPTokenオブジェクトが存在しない場合は作成。
  • Vault(LoanBroker(LoanBrokerID).VaultID)オブジェクトの状態変更

    • Vault内の利用可能な資産を減少

      • Vault.AssetsAvailable -= Loan.PrincipalRequested
    • Vaultの総価値を増加

      • Vault.AssetsTotal += LoanInterest - (LoanInterest x LoanBroker.ManagementFeeRate)(LoanInterestはローンの総利息)。
  • LoanBroker(LoanBrokerID)オブジェクトの変更

    • LoanBroker.DebtTotal += Loan.PrincipalRequested + (LoanInterest - (LoanInterest x LoanBroker.ManagementFeeRate)

    • LoanBroker.OwnerCount += 1

    • LoanBrokerDirectoryNodeが存在しない場合は作成。

      • DirectoryNode.IndexesLoanIDを追加。
3.2.1.4 不変条件

TBD

3.2.2 LoanDeleteトランザクション

このトランザクションは既存のLoanオブジェクトを削除します。

フィールド名 必須? JSONの型 内部の型 デフォルト値 説明
TransactionType 文字列 UINT16 TODO トランザクションタイプ。
LoanID 文字列 HASH256 N/A 削除するLoanオブジェクトのID。
3.2.2.1 失敗条件
  • 指定されたLoanIDを持つLoanオブジェクトがレジャー上に存在しない。
  • LoanDeleteを送信するアカウントがLoanBroker.OwnerまたはLoan.Borrowerではない。
  • ローンがアクティブ
    • Loan.PaymentsRemaining > 0
3.2.2.2 状態変更
  • LoanBrokerに関連付けられたOwner DirectoryからLoanIDを削除。
  • LoanBroker.OwnerCount -= 1
  • Loanオブジェクトを削除。
  • 準備金をBorrowerに返還。

3.2.3 LoanManageトランザクション

フィールド名 必須? JSONの型 内部の型 デフォルト値 説明
TransactionType 文字列 UINT16 TODO トランザクションタイプ。
LoanID 文字列 HASH256 N/A 更新するLoanオブジェクトのID。
Flags 文字列 UINT32 0 ローンのフラグを指定。
3.2.3.1 Flags
Flag名 Flag値 説明
tfLoanDefault 0x0001 ローンをデフォルト状態にすることを示す。
tfLoanImpair 0x0002 ローンを債務不履行状態にすることを示す。
tfLoanUnimpair 0x0003 ローンの債務不履行状態を解除することを示す。
3.2.3.1 失敗条件
  • 指定されたLoanIDを持つLoanオブジェクトがレジャー上に存在しない。

  • トランザクションを送信するAccountLoanBroker.Ownerではない。

  • ローンオブジェクトにlsfLoanDefaultフラグが設定されている。ローンがデフォルトになると、変更できない。

  • Loan(LoanID).Flags == lsfLoanImpairedかつtfLoanImpairフラグが提供されている。

  • Loan.PaymentsRemaining == 0

  • tfDefaultフラグが指定され、かつ

    • CurrentTime < Loan.NextPaymentDueDate + Loan.GracePeriod
3.2.3.2 状態変更
  • tfDefaultフラグが指定されている場合

    • First-Loss Capitalがカバーするデフォルト額を計算

      • デフォルト値は、Borrowerが未請求の資金を除く、未払いの元本と利息の合計。
        • DefaultAmount = (Loan.PrincipalOutstanding + Loan.InterestOutstanding) - Loan.AssetsAvailable
      • First-Loss Capitalをデフォルト値に適用
        • DefaultCovered = min((LoanBroker(Loan.LoanBrokerID).DebtTotal x LoanBroker(Loan.LoanBrokerID).CoverRateMinimum) x LoanBroker(Loan.LoanBrokerID).CoverRateLiquidation, DefaultAmount)
      • DefaultAmount -= DefaultCovered
    • Vaultオブジェクトを更新

      • Vaultの総価値を減少
        • Vault(LoanBroker(LoanBrokerID).VaultID).AssetsTotal -= DefaultAmount
      • Vaultの利用可能な資産を清算されたFirst-Loss Capitalと未請求の資金額分増加
        • Vault(LoanBroker(LoanBrokerID).VaultID).AssetsAvailable += DefaultCovered + Loan.AssetsAvailable
  • LoanBrokerオブジェクトを更新

    • LoanBrokerの債務を減少
      • LoanBroker(LoanBrokerID).DebtTotal -=
      • Loan.PrincipalOutstanding + Loan.InterestOutstanding + Loan.AssetsAvailable
    • 利用可能なFirst-Loss Capitalカバーを減少
      • LoanBroker(LoanBrokerID).CoverAvailable -= DefaultCovered
    • アクティブなローン数を減少
      • LoanBroker(LoanBrokerID).OwnerCount -= 1
  • Loanオブジェクトを更新

    • Loan(LoanID).Flags = lsfLoanDefault
    • Loan(LoanID).PaymentsRemaining = 0
    • Loan(LoanID).AssetsAvailable = 0
    • Loan(LoanID).PrincipalOutstanding = 0
  • tfLoanImpairフラグが指定されている場合

    • Vaultオブジェクトを更新("含み損"を設定)

      • Vault(LoanBroker(LoanBrokerID).VaultID).LossUnrealized += Loan.PrincipalOutstanding + TotalInterestOutstanding() (未払い利息の合計の計算方法については3.2.5.1. 支払いタイプセクションを参照)
    • Loanオブジェクトを更新

      • Loan(LoanID).Flags = lsfLoanImpaired
      • currentTime < Loan(LoanID).NextPaymentDueDateの場合(ローン支払いがまだ遅延していない場合)
        • Loan(LoanID).NextPaymentDueDate = currentTime (次回支払い期限を現在時刻に移動)
  • tfLoanUnimpairフラグが指定されている場合

    • Vaultオブジェクトを更新("含み損"をクリア)

    • Vault(LoanBroker(LoanBrokerID).VaultID).LossUnrealized -= Loan.PrincipalOutstanding + TotalInterestOutstanding() (未払い利息の合計の計算方法については3.2.5.1. 支払いタイプセクションを参照)

    • Loanオブジェクトを更新

      • Loan(LoanID).Flags = 0

      • Loan(LoanID).PreviousPaymentDate + Loan(LoanID).PaymentInterval > currentTimeの場合(支払い期間内にローンの債務不履行が解除された場合)

        • Loan(LoanID).NextPaymentDueDate = Loan(LoanID).PreviousPaymentDate + Loan(LoanID).PaymentInterval
      • Loan(LoanID).PreviousPaymentDate + Loan(LoanID).PaymentInterval < currentTimeの場合(元の支払い期限後にローンの債務不履行が解除された場合)

        • Loan(LoanID).NextPaymentDueDate = currentTime + Loan(LoanID).PaymentInterval
3.2.3.3 不変条件

TBD

3.2.4 LoanDrawトランザクション

Borrowerがローンから資金を引き出すためにLoanDrawトランザクションを送信します。

フィールド名 必須? JSONの型 内部の型 デフォルト値 説明
TransactionType 文字列 UINT16 TODO トランザクションタイプ。
LoanID 文字列 HASH256 N/A 引き出し元のLoanオブジェクトのID。
Amount 数値 NUMBER N/A 引き出す資金額。
3.2.4.1 失敗条件
  • 指定されたLoanIDを持つLoanオブジェクトがレジャー上に存在しない。

  • 送信者のAccountRoot.AccountLoan.Borrowerではない。

  • ローンが開始していない

    • Loan.StartDate > CurrentTime
  • 資産が不足している

    • Loan.AssetsAvailable < Amount
  • LoanlsfLoanImpairedまたはlsfLoanDefaultフラグが設定されている。

  • Vault(LoanBroker(Loan(LoanID).LoanBrokerID).VaultID).AssetIOUの場合

    • 送信者アカウントと資産のIssuer間のtrustlineがfreezeされている。
    • IssuerAccountRootオブジェクトにlsfGlobalFreezeフラグが設定されている。
  • Vault(LoanBroker(Loan(LoanID).LoanBrokerID).VaultID).AssetMPTの場合

    • 送信者のAccountRootVault(LoanBroker(Loan(LoanID).LoanBrokerID).VaultID).Assetに対するMPTokenオブジェクト
      • lsfMPTLockedフラグが設定されている。
    • Vault(LoanBroker(Loan(LoanID).LoanBrokerID).VaultID).AssetMPTokenIssuanceオブジェクトにlsfMPTLockedフラグが設定されている。
  • Borrowerが支払いを遅延

    • CurrentTime > Loan.NextPaymentDueDate
3.2.4.2 状態変更
  • Vault(LoanBroker(Loan(LoanID).LoanBrokerID).VaultID).AssetXRPの場合

    • pseudo-account AccountRootBalanceフィールドをAmount分減少。
    • 送信者のAccountRootBalanceフィールドをAmount分増加。
  • Vault(LoanBroker(Loan(LoanID).LoanBrokerID).VaultID).AssetIOUの場合

    • pseudo-account AccountRootIssuer AccountRoot間のRippleState残高をAmount分減少。
    • 送信者のAccountRootIssuer AccountRoot間のRippleState残高をAmount分増加。
  • Vault(LoanBroker(Loan(LoanID).LoanBrokerID).VaultID).AssetMPTの場合

    • Vault.Assetに対するpseudo-account MPTokenオブジェクトのMPToken.MPTAmountAmount分減少。
    • Vault.Assetに対する送信者のMPTokenオブジェクトのMPToken.MPTAmountAmount分増加。
  • Loan.AssetsAvailableAmount分減少。

3.2.4.3 不変条件

TBD

3.2.5 LoanPayトランザクション

Borrowerがローンの支払いを行うためにLoanPayトランザクションを送信します。

フィールド名 必須? JSONの型 内部の型 デフォルト値 説明
TransactionType 文字列 UINT16 TODO トランザクションタイプ。
LoanID 文字列 HASH256 N/A 支払い対象のLoanオブジェクトのID。
Amount 数値 NUMBER N/A 支払う資金額。
3.2.5.1 支払いタイプ

ローン支払いには4つのタイプがあります。

  • 標準償却計算式で計算された支払い額とスケジュールに従って期限内に行われる通常支払い。

  • netxPaymentDueDate後にBorrowerが行う 遅延 支払い。遅延支払いにはLatePaymentFeeLateInterestRateが含まれます。

  • Borrowerが未払い元本を支払う早期 全額 支払い。未払い元本に対してCloseInterestRateが課されます。

  • 借り手が必要最低支払額を超える支払いを行う超過支払い。

支払いの金額とタイミングによって支払いのタイプが決定されます。Loan.NextPaymentDueDate以前に行われる支払いは通常支払いとなり、標準償却計算に従います。この日付以降に行われる支払いは遅延支払いとみなされます。

以下の図は、支払われた金額に基づいて支払いがどのように処理されるかを示しています。

   拒否         超過支払い      超過支払い       超過支払い      請求なし
|------------|---------------|---------------|---------------|-------------|
         定期/遅延          定期              定期             全額
         支払い額         支払い額           支払い額          支払い額
            I              II              N - 1           支払い額

必要最低支払額は、借り手がNextPaymentDueDate以前に支払いを行うか、遅延するかによって決定されます。必要最低額を下回る支払いは拒否されます。借り手は単一のLoanPayトランザクションで複数のローン支払いを行うことができます。例えば、定期支払い額が400トークンで、借り手が900トークンの支払いを行った場合、その支払いは2回分の定期支払いとして扱われ、NextPaymentDueDateは2支払い期間分前進し、残りの100トークンは超過支払いとなります。

Loan Brokerと借り手が超過支払いを許可することに合意している場合、定期支払い額を超える金額は超過支払いとして扱われます。ただし、超過支払いがサポートされていない場合、超過額は請求されず、借り手の元に残ります。

各支払いは、principal(元本)、interest(利息)、fee(手数料)の3つの部分で構成されます。principalはローンの元本に対して支払われる金額、interestはローンの利息部分、feeprincipalinterestに加えて借り手が支払う手数料部分です。

3.2.5.1.1 通常支払い

定期支払い額は、元利均等返済の支払い公式を使用して計算されます。

totalDue = periodicPayment + loanServiceFee
periodicPayment = principalOutstanding \times \frac{periodicRate \times (1 + periodicRate)^{PaymentsRemaining}}{(1 + periodicRate)^{PaymentsRemaining} - 1}

ここで、定期利率は支払い期間ごとに課される利率です。

periodicRate = \frac{interestRate \times paymentInterval}{365 \times 24 \times 60 \times 60}

principalinterestの部分は次のように導出できます。

interest = principalOutstanding \times periodicRate
principal = periodicPayment - interest
3.2.5.1.2 遅延支払い

借り手がNextPaymentDueDate以降に支払いを行う場合、名目遅延支払い手数料と、未払い期間の延滞額に対して課される追加利息を支払う必要があります。計算式は以下の通りです。

totalDue = periodicPayment + latePaymentFee + latePaymentInterest

延滞期間に対して特別な遅延支払い利率が適用されます。

latePaymentInterest = principalOutstanding \times \frac{lateInterestRate \times secondsSinceLastPayment}{365 \times 24 \times 60 \times 60}

遅延支払いはLoanSetトランザクションでVault価値を増加させる際に計算された利息よりも多くの利息を支払います。したがって、Vault.AssetsTotalで捕捉されるVaultの総価値を再計算する必要があります。

PeriodicPayment()関数がprincipalPeriodicinterestPeriodicに分割された予想定期支払い額を返すと仮定します。さらに、遅延支払い計算式を実装するLatePayment()関数を仮定します。この関数は、上記の計算式を使用して計算されたprincipalLateinterestLateに分割された遅延支払いを返します。principalPeriodic == principalLateおよびinterestLate > interestPeriodicは支払いが遅延した場合にのみ使用されることに注意してください。それ以外の場合は、interestLate == interestPeriodicとなります。

valueChange = interestLate - interestPeriodic

valueChange >= 0であることに注意してください。

3.2.5.1.3 ローン超過支払い
  • \mathcal{P}\mathcal{p}をそれぞれローンの総元本と未払い元本とします。
  • \mathcal{I}\mathcal{i}をそれぞれ\mathcal{P}\mathcal{p}から計算された総利息と未払い利息とします。
excess = min(\mathcal{p}, paymentAmountMade - minimumPaymentAmount)
interestPortion = excess \times overpaymentInterestRate
feePortion = excess \times overpaymentFee
principalPortion = excess - interestPortion - feePortion
\mathcal{p'} = \mathcal{p} - principalPortion

\mathcal{i}\mathcal{p}から計算された未払い利息とします。同様に、\mathcal{i'}\mathcal{p'}から計算された未払い利息とします。ローン利息の変更を以下のように計算します。

valueChange = \mathcal{i} - \mathcal{i'}
3.2.5.1.4 早期全額返済

借り手は、全額返済に必要な総額を提出することで、ローンを早期に完済することができます。この金額は、残高、発生利息、期限前返済ペナルティ、および期限前返済手数料の合計です。

totalDue = principalOutstanding + accruedInterest + prepaymentPenalty + ClosePaymentFee

早期完済時点までの発生利息は以下のように計算されます。

accruedInterest = principalOutstanding \times periodicRate \times \frac{secondsSinceLastPayment}{paymentInterval}

最後に、Lenderはローンの早期返済に対して期限前返済ペナルティを課すことができ、これは以下のように計算されます。

prepaymentPenalty = principalOutstanding \times closeInterestRate

早期返済はLoanSetトランザクションでVault価値を増加させる際に計算された利息よりも少ない利息を支払います。したがって、Vault.AssetsTotalで捕捉されるVaultの価値は早期返済後に再計算する必要があります。

ローンのprincipalOutstandinginterestOutstandingを返すCurrentValue()関数を仮定します。さらに、全額返済の計算を実装するClosePayment()関数を仮定します。この関数はprincipalinterestに分割された支払うべき全額返済額を返します。

早期全額返済の価値変更は以下のように計算されます。

valueChange = (prepaymentPenalty) - (interestOutstanding - accruedInterest)

valueChange <= 0となることに注意してください。これは早期返済がローンの総価値を減少させるためです。

3.2.5.1.5 管理手数料の計算

LoanBroker管理手数料はローンの利息部分に対して課され、ローン作成時にローンの総価値から差し引かれます。ただし、手数料は実際にはローン支払い時にのみ課されます。早期支払いや遅延支払いは、総利息の価値を減少または増加させることでローンの総価値を変更します。したがって、早期、遅延、または超過支払いが行われた場合、管理手数料を更新する必要があります。

管理手数料を更新するには、早期または遅延支払いを実行した後の新しい総利息に基づいて、新しい総管理手数料を計算する必要があります。そのため、支払いが行われる前のローン価値と、支払い後の新しい価値を捕捉する必要があります。

計算のために、以下の変数を仮定します。

  • \mathcal{P}\mathcal{p}をそれぞれローンの総元本と未払い元本とします。
  • \mathcal{I}\mathcal{i}をそれぞれ\mathcal{P}\mathcal{p}から計算された総利息と未払い利息とします。
  • \mathcal{V}\mathcal{v}をそれぞれローンの総価値と未払い価値とします。\mathcal{V} = \mathcal{P} + \mathcal{I}および\mathcal{v} = \mathcal{p} + \mathcal{i}です。
  • 最後に、\mathcal{m}をLoan Brokerの管理手数料率とします。

f(\mathcal{v})をローン支払いとし、f(\mathcal{v}) = \mathcal{v'}とすると、新しい未払いローン価値は現在の未払い価値に対する支払いトランザクションの適用と等しくなります。さらに、\mathcal{V} \xrightarrow{f(\mathcal{v})} \mathcal{V'}f(\mathcal{v})を適用した結果としてのローン総価値の変更とします。

\mathcal{V'} = \mathcal{P'} + \mathcal{I'}と言えます。支払いトランザクションは決して総元本を変更してはならないことに注意することが重要です。つまり\mathcal{P} = \mathcal{P'}であり、総価値の変更は総元本の変更によってのみ引き起こされます。

\Delta_{\mathcal{V}} = \mathcal{I'} - \mathcal{I}はローンの総価値変更です。\Delta_{\mathcal{V}} > 0の場合、ローンの総価値は増加し、\Delta_{\mathcal{V}} < 0の場合は総価値が減少し、\Delta_{\mathcal{V}} = 0の場合は価値は変わりません。

総管理手数料は以下のように計算されます。

managementFeeTotal = \mathcal{I} \times \mathcal{m}

これまでに支払われた管理手数料を以下のように計算します。

managementFeePaid = (\mathcal{I} - \mathcal{i}) \times \mathcal{m}
managementFeeDue = managementFeeTotal - managementFeePaid

最後に、管理手数料の変更を以下のように計算します。

managementFeeChange = \mathcal{i'} \times \mathcal{m} - managementFeeDue

上記の計算は以下のように簡略化できます。

managementFeeChange = \Delta_{\mathcal{V}} \times \mathcal{m}

管理手数料の変更が負の場合、ローンの価値は減少し、したがってLoan Brokerの債務も減少します。
直感的に、負の手数料変更は手数料を返還する必要があることを示唆し、これによってloan brokerの債務が増加します。

対照的に、管理手数料の変更が正の場合、ローンの価値は増加し、さらなる手数料を債務から差し引く必要があります。
直感的に、正の手数料変更は支払われる利息の増加により追加の手数料を支払う必要があることを示唆します。

LoanBrokerの債務は以下のように更新されます。

LoanBroker.DebtTotal = LoanBroker.DebtTotal - managementFeeChange
3.2.5.2 トランザクションの疑似コード

以下はローン支払いトランザクションを処理するための疑似コードです。

function make_payment(amount, current_time) -> (principal_paid, interest_paid, value_change, fee_paid):
    if loan.payments_remaining is 0 || loan.principal_outstanding is 0 {
        return "loan complete" error
    }

    // 支払いが遅延している場合
    if loan.next_payment_due_date < current_time {
        let late_payment = loan.compute_late_payment(current_time)
        if amount < late_payment {
            return "insufficient amount paid" error
        }

        loan.payments_remaining -= 1
        loan.principal_outstanding -= late_payment.principal

        loan.last_payment_date = loan.next_payment_due_date
        loan.next_payment_due_date = loan.next_payment_due_date + loan.payment_interval

        let periodic_payment = loan.compute_periodic_payment()

        // 遅延支払いはローンの価値を定期支払いと遅延支払いの利息の差分だけ増加させる
        return (late_payment.principal, late_payment.interest, late_payment.interest - periodic_payment.interest, loan.late_payment_fee)
    }

    let full_payment = loan.compute_full_payment(current_time)

    // 支払額が全額返済額以上で、かつ1回以上の支払いが残っている場合は
    // 全額返済を行う
    if amount >= full_payment && loan.payments_remaining > 1 {
        loan.payments_remaining = 0
        loan.principal_outstanding = 0

        // 全額返済はローンの価値を支払われた利息と予想される未払い利息の差分だけ減少させる
        return (full_payment.principal, full_payment.interest, full_payment.interest - loan.compute_current_value().interest, full_payment.fee)
    }

    // 支払いが遅延でもなく全額返済でもない場合は定期支払い

    let periodic_payment = loan.compute_periodic_payment()

    let full_periodic_payments = floor(amount / periodic_payment)
    if full_periodic_payments < 1 {
        return "insufficient amount paid" error
    }

    loan.payments_remaining -= full_periodic_payments
    loan.next_payment_due_date = loan.next_payment_due_date + loan.payment_interval * full_periodic_payments
    loan.last_payment_date = loan.next_payment_due_date - loan.payment_interval


    let total_principal_paid = 0
    let total_interest_paid = 0
    let loan_value_change = 0
    let total_fee_paid = loan.service_fee * full_periodic_payments

    while full_periodic_payments > 0 {
        total_principal_paid += periodic_payment.principal
        total_interest_paid += periodic_payment.interest
        periodic_payment = loan.compute_periodic_payment()
        full_periodic_payments -= 1
    }

    loan.principal_outstanding -= total_principal_paid

    let overpayment = min(loan.principal_outstanding, amount % periodic_payment)
    if overpayment > 0 && is_set(lsfOverPayment) {
        let interest_portion = overpayment * loan.overpayment_interest_rate
        let fee_portion = overpayment * loan.overpayment_fee
        let remainder = overpayment - interest_portion - fee_portion

        total_principal_paid += remainder
        total_interest_paid += interest_portion
        total_fee_paid += fee_portion

        let current_value = loan.compute_current_value()
        loan.principal_outstanding -= remainder
        let new_value = loan.compute_current_value()

        loan_value_change = (new_value.interest - current_value.interest) + interest_portion
    }

    return (total_principal_paid, total_interest_paid, loan_value_change, total_fee_paid)
}
3.2.5.3 失敗条件
  • 指定されたLoanIDを持つLoanオブジェクトがledger上に存在しない。

  • ローンがまだ開始していない: Loan.StartDate > CurrentTime

  • トランザクション送信者のAccountRoot.AccountLoan.Borrowerと等しくない。

  • Loan.PaymentsRemainingまたはLoan.PrincipalOutstanding0

  • Vault(LoanBroker(Loan(LoanID).LoanBrokerID).VaultID).AssetIOUの場合

    • 送信者アカウントと資産のIssuer間のトラストラインがフリーズされている。
    • IssuerAccountRootオブジェクトにlsfGlobalFreezeフラグが設定されている。
  • Vault(LoanBroker(Loan(LoanID).LoanBrokerID).VaultID).AssetMPTの場合

    • 送信者のAccountRootVault(LoanBroker(Loan(LoanID).LoanBrokerID).VaultID).Assetに対するMPTokenオブジェクト
      • lsfMPTLockedフラグが設定されている。
    • Vault(LoanBroker(Loan(LoanID).LoanBrokerID).VaultID).AssetMPTokenIssuanceオブジェクトにlsfMPTLockedフラグが設定されている。
  • CurrentTime > Loan.NextPaymentDueDateかつAmount < LatePaymentAmount()

  • CurrentTime <= Loan.NextPaymentDueDateかつAmount < PeriodicPaymentAmount()

3.2.5.4 状態変更

支払いがprincipalinterestfeeに分割され、totalDue = principal + interest + feeと仮定します。

疑似コードを実装する関数によって支払いが処理され、principal_paidinterest_paidvalue_changefee_paidを返すと仮定します。

  • principal_paidは支払いがカバーした元本額
  • interest_paidは支払いがカバーした利息額
  • fee_paidは支払いがカバーした手数料額
  • value_changeはローンの総価値が変化した額
    • value_change < 0の場合、ローン価値は減少
    • value_change > 0の場合、ローン価値は増加

さらに、full_periodic_payments変数は支払いがカバーした支払い期間の数を表すと仮定します。

  • Loanオブジェクトの状態変更

    • Loan(LoanID).Flags == lsfLoanImpairedの場合

      • Loan(LoanID).Flags = 0
    • Loan.PaymentsRemainingfull_periodic_paymentsだけ減少

    • Loan.PrincipalOutstandingprincipal_paidだけ減少

    • Loan.PaymentsRemaining > 0かつLoanPrincipalOutstanding > 0の場合

      • 次回支払い日を設定: Loan.NextPaymentDueDate += Loan.PaymentInterval * full_periodic_payments
      • 前回支払い日を設定: Loan.PreviousPaymentDate = Loan.NextPaymentDueDate - Loan.PaymentInterval
  • LoanBroker(Loan.LoanBrokerID)オブジェクトの状態変更

    • 管理手数料を計算

      • feeManagement = interest_paid x LoanBroker.ManagementFeeRate
    • First-Loss Capitalが不十分な場合LoanBroker.CoverAvailable < LoanBroker.DebtTotal x LoanBroker.CoverRateMinimum

      • 管理手数料を課さず、総債務に追加
        • LoanBroker.DebtTotal += feeManagement
    • First-Loss Capitalが十分な場合LoanBroker.CoverAvailable >= LoanBroker.DebtTotal x LoanBroker.CoverRateMinimum

      • 支払総額から管理手数料を減少
        • totalPaid = totalPaid - feeManagement
    • 支払額だけLoanBrokerの債務を減少

      • LoanBroker.DebtTotal -= totalPaid
    • ローン価値の変更によってLoanBrokerの債務を更新

      • LoanBroker.DebtTotal += valueChange
    • 管理手数料の変更によってLoanBrokerの債務を更新

      • LoanBroker.DebtTotal -= (valueChange x LoanBroker.ManagementFeeRate)
    • LoanPaymentsRemaining == 0かつLoanPrincipalOutstanding == 0の場合

      • アクティブローンを減少
        • LoanBroker.OwnerCount = LoanBroker.OwnerCount - 1
  • Vault(LoanBroker(Loan.LoanBrokerID).VaultID)オブジェクトの状態変更

    • Vault内の利用可能な資産を支払額だけ増加

      • Vault.AssetsAvailable = Vault.AssetsAvailable + totalPaid
    • ローンの総価値の変更によってVaultの総価値を更新

      • Vault.AssetsTotal = Vault.AssetsTotal + valueChange
    • 管理手数料の変更によってVaultの総価値を更新

      • Vault.AssetsTotal = Vault.AssetsTotal - (vaultChange x LoanBroker.managementFeeRate)
    • First-Loss Capitalが不十分な場合LoanBroker.CoverAvailable < LoanBroker.DebtTotal x LoanBroker.CoverRateMinimum

      • 管理手数料が課されなかったため、Vaultの総価値を減少
        • Loan.AssetsTotal = Loan.AssetsTotal + feeManagement
  • Vault(LoanBroker(Loan(LoanID).LoanBrokerID).VaultID).AssetXRPの場合

    • pseudo-account AccountRootBalanceフィールドをprincipal_paid + (interest_paid - management_fee)だけ増加。

    • LoanBroker.CoverAvailable >= LoanBroker.DebtTotal x LoanBroker.CoverRateMinimumの場合

      • LoanBroker.Owner AccountRootBalanceフィールドをfee_paid + management_feeだけ増加。
    • 送信者のAccountRootBalanceフィールドをprincipal_paid + interest_paid + fee_paidだけ減少。

  • Vault(LoanBroker(Loan(LoanID).LoanBrokerID).VaultID).AssetIOUの場合

    • pseudo-account AccountRootIssuer AccountRoot間のRippleState残高をprincipal_paid + (interest_paid - management_fee)だけ増加。

    • LoanBroker.CoverAvailable >= LoanBroker.DebtTotal x LoanBroker.CoverRateMinimumの場合

      • LoanBroker.Owner AccountRootIssuer AccountRoot間のRippleState残高をfee_paid + management_feeだけ増加。
    • 送信者のAccountRootIssuer AccountRoot間のRippleState残高をprincipal_paid + interest_paid + fee_paidだけ減少。

  • Vault(LoanBroker(Loan(LoanID).LoanBrokerID).VaultID).AssetMPTの場合

    • pseudo-accountのVault.Assetに対するMPTokenオブジェクトのMPToken.MPTAmountprincipal_paid + (interest_paid - management_fee)だけ増加。

    • LoanBroker.CoverAvailable >= LoanBroker.DebtTotal x LoanBroker.CoverRateMinimumの場合

      • LoanBroker.OwnerVault.Assetに対するMPTokenオブジェクトのMPToken.MPTAmountfee_paid + management_feeだけ増加。
    • 送信者のVault.Assetに対するMPTokenオブジェクトのMPToken.MPTAmountprincipal_paid + interest_paid + fee_paidだけ減少。

3.2.5.4 不変条件

TBD

Discussion