You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: XLS-0066-lending-protocol/README.md
+91-49Lines changed: 91 additions & 49 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -158,7 +158,15 @@ The `LoanBroker` object has the following fields:
158
158
|`CoverRateLiquidation`| No | Yes |`number`|`UINT32`| 0 | The 1/10th basis point of minimum required first-loss capital that is liquidated to cover a Loan default. Valid values are between 0 and 100000 inclusive. A value of 1 is equivalent to 1/10 bps or 0.001%. |
159
159
|`DomainID`| No | No |`string`|`HASH256`| None | The `PermissionedDomain` object ID associated with the `LoanBroker`. |
160
160
161
-
#### 3.1.3 Ownership
161
+
#### 3.1.3 Flags
162
+
163
+
The `LoanBroker` object supports the following flags:
164
+
165
+
| Flag Name | Flag Value | Modifiable? | Description |
|`lsfLoanBrokerPrivate`|`0x00010000`|`No`| If set, indicates that the `LoanBroker` is private. |
168
+
169
+
#### 3.1.4 Ownership
162
170
163
171
The lending protocol object is stored in the ledger and tracked in an [Owner Directory](https://xrpl.org/docs/references/protocol/ledger-data/ledger-entry-types/directorynode) owned by the account submitting the `LoanBrokerSet` transaction. Furthermore, the object is also tracked in the `OwnerDirectory` of the `Vault`_`pseudo-account`_. The `_pseudo_account_``OwnerDirectory` page is captured by the `VaultNode` field.
164
172
@@ -167,23 +175,23 @@ The `RootIndex` of the `DirectoryNode` object is the result of [`SHA512-Half`](h
167
175
- The `OwnerDirectory` space key `0x004F`
168
176
- The `LoanBrokerID`
169
177
170
-
#### 3.1.4 Reserves
178
+
#### 3.1.5 Reserves
171
179
172
180
The `LoanBroker` object costs two owner reserve for the account creating it.
173
181
174
-
#### 3.1.5 Deletion
182
+
#### 3.1.6 Deletion
175
183
176
184
- All Loans associated with the LoanBroker must be deleted first.
177
185
- The LoanBroker must have no outstanding debt owed to the Vault.
178
186
- Any remaining First-Loss Capital is automatically transferred back to the broker owner upon deletion. The deletion will fail if the broker owner is deep frozen for the asset, preventing the return of funds.
179
187
180
188
**Account Deletion Blocker:** Yes. This object must be deleted before its owner account can be deleted.
181
189
182
-
#### 3.1.6 Pseudo-Account
190
+
#### 3.1.7 Pseudo-Account
183
191
184
192
The `LoanBroker` object _pseudo-account_ holds the First-Loss Capital deposited by the LoanBroker. The _pseudo-account_ follows the XLS-64d specification for pseudo accounts. The `AccountRoot` object is created when creating the `Vault` object.
185
193
186
-
#### 3.1.7 Freeze/Lock
194
+
#### 3.1.8 Freeze/Lock
187
195
188
196
The `LoanBroker`_pseudo-account_ can be frozen or locked by the asset Issuer. The effects depend on the freeze level:
189
197
@@ -211,11 +219,11 @@ The `LoanBroker` _pseudo-account_ can be frozen or locked by the asset Issuer. T
211
219
212
220
- Prevents all Loan creation, Loan payments, and First-Loss Capital deposits/withdrawals for the affected asset.
The Lending Protocol tracks the funds owed to the associated Vault in the `DebtTotal` attribute. It captures the principal amount taken from the Vault and the interest due, excluding all fees. The `DebtMaximum` attribute controls the maximum debt a Lending Protocol may incur. Whenever the Lender issues a Loan, `DebtTotal` is incremented by the Loan principal and interest, excluding fees. When $DebtTotal \geq DebtMaximum$, the Lender cannot issue new loans until some of the debt is cleared. Furthermore, the Lender may not issue a loan that would cause the `DebtTotal` to exceed `DebtMaximum`.
The First-Loss Capital is an optional mechanism to protect the Vault depositors from incurring a loss in case of a Loan default by absorbing some of the loss. The following parameters control this mechanism:
A Loan Issuer may want to ensure that all Borrowers meet certain legal obligations, such as KYC. This can be done by attaching a [Permissioned Domain](../XLS-0080-permissioned-domains/README.md), which restricts Loans to accounts with specific credentials. Only accounts with the required credentials can take out loans from a private LoanBroker. To configure a LoanBroker as private, set the `lsfLoanBrokerPrivate` flag when creating the `LoanBroker` object. If this flag is enabled, the LoanBroker is private. If the flag is not set, the LoanBroker is public, and any account may take out a loan.
404
+
405
+
The presence or absence of a Permissioned Domain does not affect the signature requirements for the `LoanSet` transaction. Both the LoanBroker Owner and the Borrower must sign the `LoanSet` transaction, ensuring that even if an account is included in the Permissioned Domain, both parties must explicitly authorise the transaction.
406
+
407
+
The LoanBroker Owner can clear or change the associated Permissioned Domain. If a private LoanBroker does not have a Permissioned Domain attached, loans cannot be issued until one is configured. Removing or changing the Permissioned Domain does not affect the `LoanPay` transaction for existing or new loans. Borrowers can always make loan payments. **Note**, the LoanBroker Owner does not need credentials in the Permissioned Domain to issue a loan to a Borrower. However, if the Owner wishes to take out a loan from their own LoanBroker, they must hold the required credentials.
408
+
392
409
### 3.2. Ledger Entry: `Loan`
393
410
394
411
A Loan ledger entry captures various Loan terms on-chain. It is an agreement between the Borrower and the loan issuer.
@@ -563,15 +580,21 @@ The transaction creates a new `LoanBroker` object or updates an existing one.
563
580
|`DebtMaximum`| No |`string`|`NUMBER`| 0 | The maximum amount the protocol can owe the Vault. The default value of 0 means there is no limit to the debt. Must not be negative. |
564
581
|`CoverRateMinimum`| No |`number`|`UINT32`| 0 | The 1/10th basis point `DebtTotal` that the first-loss capital must cover. Valid values are between 0 and 100000 inclusive. |
565
582
|`CoverRateLiquidation`| No |`number`|`UINT32`| 0 | The 1/10th basis point of minimum required first-loss capital liquidated to cover a Loan default. Valid values are between 0 and 100000 inclusive. |
566
-
|`DomainID`| No |`string`|`HASH256`| Empty | TThe `PermissionedDomain` object ID associated with the `LoanBroker`. |
583
+
|`DomainID`| No |`string`|`HASH256`| Empty | The `PermissionedDomain` object ID associated with the `LoanBroker`. |
|`tfLoanBrokerPrivate`|`0x00010000`| Indicates that the `LoanBroker` is private. It can only be set during `LoanBroker` creation. |
590
+
591
+
#### 3.3.3 Transaction Fee
569
592
570
593
This transaction uses the standard transaction fee.
571
594
572
-
#### 3.3.3 Failure Conditions
595
+
#### 3.3.4 Failure Conditions
573
596
574
-
##### 3.3.3.1 Data Verification
597
+
##### 3.3.4.1 Data Verification
575
598
576
599
1.`VaultID` is zero. (`temINVALID`)
577
600
2.`Data` field is present, non-empty, and exceeds 256 bytes. (`temINVALID`)
@@ -580,11 +603,17 @@ This transaction uses the standard transaction fee.
580
603
5.`CoverRateLiquidation` is outside valid range (0 to 100000). (`temINVALID`)
581
604
6.`DebtMaximum` is negative or exceeds maximum allowed value. (`temINVALID`)
582
605
7. One of `CoverRateMinimum` and `CoverRateLiquidation` is zero, and the other one is not. (Either both are zero, or both are non-zero) (`temINVALID`)
583
-
8.`LoanBrokerID` is specified and is zero. (`temINVALID`)
584
-
9.`LoanBrokerID` is specified and the submitter is attempting to modify fixed fields (`ManagementFeeRate`, `CoverRateMinimum`, `CoverRateLiquidation`). (`temINVALID`)
585
-
10.`DomainID` is provided but is zero. (`temMALFORMED`)
586
606
587
-
##### 3.3.3.2 Protocol-Level Failures
607
+
8. If `LoanBrokerID` is **not** specified (creating new):
608
+
1.`DomainID` is provided and is zero. (`temMALFORMED`)
609
+
2.`DomainID` is provided, and the `tfLoanBrokerPrivate` flag is not set. (`temINVALID`)
610
+
611
+
9. If `LoanBrokerID` is specified (modifying existing):
612
+
1.`LoanBrokerID` is empty. (`temINVALID`)
613
+
2. Submitter is attempting to modify fixed fields (`ManagementFeeRate`, `CoverRateMinimum`, `CoverRateLiquidation`). (`temINVALID`)
614
+
3. Submitter is attempting to modify `tfLoanBrokerPrivate` flag on an existing `LoanBroker`. (`temINVALID`)
615
+
616
+
##### 3.3.4.2 Protocol-Level Failures
588
617
589
618
**If `LoanBrokerID` is not specified (creating new):**
590
619
@@ -601,13 +630,14 @@ This transaction uses the standard transaction fee.
601
630
2. The submitter `AccountRoot.Account != LoanBroker(LoanBrokerID).Owner`. (`tecNO_PERMISSION`)
602
631
3. The transaction `VaultID` does not match `LoanBroker(LoanBrokerID).VaultID`. (`tecNO_PERMISSION`)
603
632
4.`DebtMaximum` is being reduced to a non-zero value below the current `DebtTotal`. (`tecLIMIT_EXCEEDED`)
604
-
5.`DomainID` is provided, is non-zero, and the `PermissionedDomain` object does not exist. (`tecOBJECT_NOT_FOUND`)
633
+
5.`DomainID` is provided, is non-zero and `LoanBroker.lsfLoanBrokerPrivate` flag is not set. (`tecNO_PERMISSION`)
634
+
6.`DomainID` is provided, is non-zero, and the `PermissionedDomain` object does not exist. (`tecOBJECT_NOT_FOUND`)
605
635
606
636
**Precision Validation:**
607
637
608
638
1. Any value field (e.g., `DebtMaximum`) cannot be represented in the `Vault.Asset` type without precision loss (relevant for XRP and MPT). (`tecPRECISION_LOSS`)
609
639
610
-
#### 3.3.4 State Changes
640
+
#### 3.3.5 State Changes
611
641
612
642
**If `LoanBrokerID` is not specified (creating new):**
613
643
@@ -629,21 +659,29 @@ This transaction uses the standard transaction fee.
629
659
5. Update submitting account:
630
660
- Increment the submitting account's `OwnerCount` by 2 (one for the `LoanBroker` object, one for the _pseudo-account_).
631
661
632
-
6. If `DomainID` is provided:
662
+
6. If `tfLoanBrokerPrivate` flag is set in the transaction:
663
+
1.`LoanBroker.Flags |= lsfLoanBrokerPrivate` (Set that LoanBroker is private).
664
+
665
+
7. If `DomainID` is provided:
633
666
1. Set `LoanBroker.DomainID = DomainID` (Set the Permissioned Domain).
634
667
635
668
**If `LoanBrokerID` is specified (modifying existing):**
636
669
637
670
1. Update `LoanBroker.Data` if provided in the transaction.
638
671
2. Update `LoanBroker.DebtMaximum` if provided in the transaction.
639
-
3. If `DomainID` is provided:
672
+
673
+
3. If `DomainID` is provided and is non-zero:
640
674
1. Set `LoanBroker.DomainID = DomainID` (Set the Permissioned Domain).
641
675
642
-
#### 3.3.5 Invariants
676
+
4. If `DomainID` is provided and is zero:
677
+
1. Clear `LoanBroker.DomainID` (Unset the Permissioned Domain).
643
678
644
-
**TBD**
679
+
#### 3.3.6 Invariants
645
680
646
-
#### 3.3.6 Example JSON
681
+
1. If `LoanBroker.lsfLoanBrokerPrivate` flag is set, it cannot be unset.
682
+
2. If `LoanBroker.DomainID` field is present, `LoanBroker.lsfLoanBrokerPrivate` flag must be set.
683
+
684
+
#### 3.3.7 Example JSON
647
685
648
686
```json
649
687
{
@@ -1071,33 +1109,37 @@ The account specified in the `Account` field pays the transaction fee.
1071
1109
14.`PaymentTotal <= 0`. (`temINVALID`)
1072
1110
15.`PaymentInterval` is less than `60` seconds. (`temINVALID`)
1073
1111
16.`GracePeriod` is less than `60` seconds or greater than the `PaymentInterval`. (`temINVALID`)
1112
+
17. The `Counterparty` field is not specified and the `CounterpartySignature` is not from the `LoanBroker.Owner`. (`temBAD_SIGNER`)
1074
1113
1075
1114
##### 3.8.5.2 Protocol-Level Failures
1076
1115
1077
-
1. The `Counterparty` field is not specified and the `CounterpartySignature` is not from the `LoanBroker.Owner`. (`temBAD_SIGNER`)
1078
-
2. The loan schedule (`PaymentInterval × PaymentTotal + GracePeriod`) would overflow protocol time limits. (`tecKILLED`)
1079
-
3.`LoanBroker` object with the specified `LoanBrokerID` does not exist on the ledger. (`tecNO_ENTRY`)
1080
-
4. Neither the `Account` nor the `Counterparty` field are the `LoanBroker.Owner`. (`tecNO_PERMISSION`)
1081
-
5. The `Borrower``AccountRoot` object does not exist. (`terNO_ACCOUNT`)
1082
-
6.`Vault.AssetsMaximum != 0` and `Vault.AssetsTotal >= Vault.AssetsMaximum` (vault at capacity). (`tecLIMIT_EXCEEDED`)
1083
-
7. Any value field (e.g., `PrincipalRequested`, `LoanOriginationFee`) cannot be represented in the `Vault.Asset` type without precision loss. (`tecPRECISION_LOSS`)
1084
-
8. Cannot add asset holding for the `Vault.Asset` (e.g., MPToken or TrustLine issues). (`tecNO_PERMISSION`)
1085
-
9. The Vault _pseudo-account_ is frozen for the asset. (`tecFROZEN` for IOUs, `tecLOCKED` for MPTs)
1086
-
10. The LoanBroker _pseudo-account_ is deep frozen for the asset. (`tecFROZEN` for IOUs, `tecLOCKED` for MPTs)
1087
-
11. The Borrower is frozen for the asset. (`tecFROZEN` for IOUs, `tecLOCKED` for MPTs)
1088
-
12. The `LoanBroker.Owner` is deep frozen for the asset. (`tecFROZEN` for IOUs, `tecLOCKED` for MPTs)
1089
-
13.`Vault.AssetsAvailable < PrincipalRequested` (insufficient assets in the Vault). (`tecINSUFFICIENT_FUNDS`)
1090
-
14.`Vault.AssetsMaximum != 0` and `Vault.AssetsTotal + InterestDue > Vault.AssetsMaximum` (expected interest would exceed vault assets cap). (`tecLIMIT_EXCEEDED`)
1091
-
15. The combination of `PrincipalRequested`, `InterestRate`, `PaymentTotal`, and `PaymentInterval` results in a total interest amount that is zero or negative due to precision limitations. (`tecPRECISION_LOSS`)
1092
-
16. The loan terms result in a periodic payment that is too small to cover the interest accrued in the first period, leaving no amount to pay down the principal. (`tecPRECISION_LOSS`)
1093
-
17. The calculated periodic payment is so small that it rounds down to zero when adjusted for the asset's precision. (`tecPRECISION_LOSS`)
1094
-
18. The rounding of the periodic payment (due to asset precision) is significant enough that the total number of payments required to settle the loan differs from the specified `PaymentTotal`. (`tecPRECISION_LOSS`)
1095
-
19.`LoanBroker.DebtMaximum != 0` and `LoanBroker.DebtMaximum < LoanBroker.DebtTotal + PrincipalRequested + InterestDue` (exceeds maximum debt). (`tecLIMIT_EXCEEDED`)
21. The Borrower does not have sufficient reserve for the `Loan` object. (`tecINSUFFICIENT_RESERVE`)
1098
-
22. The Borrower is not authorized for the asset. (`tecNO_AUTH`)
1099
-
23. The `LoanBroker.Owner` is not authorized for the asset. (`tecNO_AUTH`)
1100
-
24. The `LoanBroker.LoanSequence` has reached its maximum value. (`tecMAX_SEQUENCE_REACHED`)
1116
+
1. The loan schedule (`PaymentInterval × PaymentTotal + GracePeriod`) would overflow protocol time limits. (`tecKILLED`)
1117
+
2.`LoanBroker` object with the specified `LoanBrokerID` does not exist on the ledger. (`tecNO_ENTRY`)
1118
+
3. Neither the `Account` nor the `Counterparty` field are the `LoanBroker.Owner`. (`tecNO_PERMISSION`)
1119
+
4. The `Borrower``AccountRoot` object does not exist. (`terNO_ACCOUNT`)
1120
+
5.`Vault.AssetsMaximum != 0` and `Vault.AssetsTotal >= Vault.AssetsMaximum` (vault at capacity). (`tecLIMIT_EXCEEDED`)
1121
+
6. Any value field (e.g., `PrincipalRequested`, `LoanOriginationFee`) cannot be represented in the `Vault.Asset` type without precision loss. (`tecPRECISION_LOSS`)
1122
+
7. Cannot add asset holding for the `Vault.Asset` (e.g., MPToken or TrustLine issues). (`tecNO_PERMISSION`)
1123
+
8. The Vault _pseudo-account_ is frozen for the asset. (`tecFROZEN` for IOUs, `tecLOCKED` for MPTs)
1124
+
9. The LoanBroker _pseudo-account_ is deep frozen for the asset. (`tecFROZEN` for IOUs, `tecLOCKED` for MPTs)
1125
+
10. The Borrower is frozen for the asset. (`tecFROZEN` for IOUs, `tecLOCKED` for MPTs)
1126
+
11. The `LoanBroker.Owner` is deep frozen for the asset. (`tecFROZEN` for IOUs, `tecLOCKED` for MPTs)
1127
+
12.`Vault.AssetsAvailable < PrincipalRequested` (insufficient assets in the Vault). (`tecINSUFFICIENT_FUNDS`)
1128
+
13.`Vault.AssetsMaximum != 0` and `Vault.AssetsTotal + InterestDue > Vault.AssetsMaximum` (expected interest would exceed vault assets cap). (`tecLIMIT_EXCEEDED`)
1129
+
14. The combination of `PrincipalRequested`, `InterestRate`, `PaymentTotal`, and `PaymentInterval` results in a total interest amount that is zero or negative due to precision limitations. (`tecPRECISION_LOSS`)
1130
+
15. The loan terms result in a periodic payment that is too small to cover the interest accrued in the first period, leaving no amount to pay down the principal. (`tecPRECISION_LOSS`)
1131
+
16. The calculated periodic payment is so small that it rounds down to zero when adjusted for the asset's precision. (`tecPRECISION_LOSS`)
1132
+
17. The rounding of the periodic payment (due to asset precision) is significant enough that the total number of payments required to settle the loan differs from the specified `PaymentTotal`. (`tecPRECISION_LOSS`)
1133
+
18.`LoanBroker.DebtMaximum != 0` and `LoanBroker.DebtMaximum < LoanBroker.DebtTotal + PrincipalRequested + InterestDue` (exceeds maximum debt). (`tecLIMIT_EXCEEDED`)
0 commit comments