Skip to content

Commit 74be5ae

Browse files
committed
adds PermissionedDomain to LoanBroker
1 parent f9a13c8 commit 74be5ae

File tree

1 file changed

+91
-49
lines changed

1 file changed

+91
-49
lines changed

XLS-0066-lending-protocol/README.md

Lines changed: 91 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,15 @@ The `LoanBroker` object has the following fields:
158158
| `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%. |
159159
| `DomainID` | No | No | `string` | `HASH256` | None | The `PermissionedDomain` object ID associated with the `LoanBroker`. |
160160

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 |
166+
| ---------------------- | :----------: | :---------: | --------------------------------------------------- |
167+
| `lsfLoanBrokerPrivate` | `0x00010000` | `No` | If set, indicates that the `LoanBroker` is private. |
168+
169+
#### 3.1.4 Ownership
162170

163171
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.
164172

@@ -167,23 +175,23 @@ The `RootIndex` of the `DirectoryNode` object is the result of [`SHA512-Half`](h
167175
- The `OwnerDirectory` space key `0x004F`
168176
- The `LoanBrokerID`
169177

170-
#### 3.1.4 Reserves
178+
#### 3.1.5 Reserves
171179

172180
The `LoanBroker` object costs two owner reserve for the account creating it.
173181

174-
#### 3.1.5 Deletion
182+
#### 3.1.6 Deletion
175183

176184
- All Loans associated with the LoanBroker must be deleted first.
177185
- The LoanBroker must have no outstanding debt owed to the Vault.
178186
- 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.
179187

180188
**Account Deletion Blocker:** Yes. This object must be deleted before its owner account can be deleted.
181189

182-
#### 3.1.6 Pseudo-Account
190+
#### 3.1.7 Pseudo-Account
183191

184192
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.
185193

186-
#### 3.1.7 Freeze/Lock
194+
#### 3.1.8 Freeze/Lock
187195

188196
The `LoanBroker` _pseudo-account_ can be frozen or locked by the asset Issuer. The effects depend on the freeze level:
189197

@@ -211,11 +219,11 @@ The `LoanBroker` _pseudo-account_ can be frozen or locked by the asset Issuer. T
211219

212220
- Prevents all Loan creation, Loan payments, and First-Loss Capital deposits/withdrawals for the affected asset.
213221

214-
#### 3.1.8 Invariants
222+
#### 3.1.9 Invariants
215223

216224
_TBD_
217225

218-
#### 3.1.9 Example JSON
226+
#### 3.1.10 Example JSON
219227

220228
```json
221229
{
@@ -233,11 +241,12 @@ _TBD_
233241
"OwnerCount": 1,
234242
"DebtTotal": "1000.003710049006",
235243
"CoverAvailable": "500",
236-
"index": "18D3057DC8297940B1790354455A9108BA15760B3FBD85748137751FB781C311"
244+
"index": "18D3057DC8297940B1790354455A9108BA15760B3FBD85748137751FB781C311",
245+
"DomainID": "B0F7A9C9E1F3B2C8D4E5F67890ABCDEF1234567890ABCDEFFEDCBA0987654321"
237246
}
238247
```
239248

240-
#### 3.1.10 Accounting
249+
#### 3.1.11 Accounting
241250

242251
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`.
243252

@@ -323,7 +332,7 @@ Lending Protocol:
323332
- DebtTotal = DebtTotal − PaymentPrincipalPortion − (PaymentInterestPortion − (PaymentInterestPortion × ManagementFeeRate))
324333
= 1,090 − 500 − (50 − (50 × 0.1)) = **545 Tokens**
325334

326-
#### 3.1.11 First-Loss Capital
335+
#### 3.1.12 First-Loss Capital
327336

328337
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:
329338

@@ -389,6 +398,14 @@ Lending Protocol:
389398
- CoverAvailable = CoverAvailable − DefaultCovered
390399
= 1,000 − 10.9 = **989.1 Tokens**
391400

401+
#### 3.1.13 Access Control
402+
403+
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+
392409
### 3.2. Ledger Entry: `Loan`
393410

394411
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.
563580
| `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. |
564581
| `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. |
565582
| `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`. |
584+
585+
#### 3.3.2 Flags
567586

568-
#### 3.3.2 Transaction Fee
587+
| Flag Name | Flag Value | Description |
588+
| --------------------- | :----------: | :------------------------------------------------------------------------------------------- |
589+
| `tfLoanBrokerPrivate` | `0x00010000` | Indicates that the `LoanBroker` is private. It can only be set during `LoanBroker` creation. |
590+
591+
#### 3.3.3 Transaction Fee
569592

570593
This transaction uses the standard transaction fee.
571594

572-
#### 3.3.3 Failure Conditions
595+
#### 3.3.4 Failure Conditions
573596

574-
##### 3.3.3.1 Data Verification
597+
##### 3.3.4.1 Data Verification
575598

576599
1. `VaultID` is zero. (`temINVALID`)
577600
2. `Data` field is present, non-empty, and exceeds 256 bytes. (`temINVALID`)
@@ -580,11 +603,17 @@ This transaction uses the standard transaction fee.
580603
5. `CoverRateLiquidation` is outside valid range (0 to 100000). (`temINVALID`)
581604
6. `DebtMaximum` is negative or exceeds maximum allowed value. (`temINVALID`)
582605
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`)
586606

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
588617

589618
**If `LoanBrokerID` is not specified (creating new):**
590619

@@ -601,13 +630,14 @@ This transaction uses the standard transaction fee.
601630
2. The submitter `AccountRoot.Account != LoanBroker(LoanBrokerID).Owner`. (`tecNO_PERMISSION`)
602631
3. The transaction `VaultID` does not match `LoanBroker(LoanBrokerID).VaultID`. (`tecNO_PERMISSION`)
603632
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`)
605635

606636
**Precision Validation:**
607637

608638
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`)
609639

610-
#### 3.3.4 State Changes
640+
#### 3.3.5 State Changes
611641

612642
**If `LoanBrokerID` is not specified (creating new):**
613643

@@ -629,21 +659,29 @@ This transaction uses the standard transaction fee.
629659
5. Update submitting account:
630660
- Increment the submitting account's `OwnerCount` by 2 (one for the `LoanBroker` object, one for the _pseudo-account_).
631661

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:
633666
1. Set `LoanBroker.DomainID = DomainID` (Set the Permissioned Domain).
634667

635668
**If `LoanBrokerID` is specified (modifying existing):**
636669

637670
1. Update `LoanBroker.Data` if provided in the transaction.
638671
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:
640674
1. Set `LoanBroker.DomainID = DomainID` (Set the Permissioned Domain).
641675

642-
#### 3.3.5 Invariants
676+
4. If `DomainID` is provided and is zero:
677+
1. Clear `LoanBroker.DomainID` (Unset the Permissioned Domain).
643678

644-
**TBD**
679+
#### 3.3.6 Invariants
645680

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
647685

648686
```json
649687
{
@@ -1071,33 +1109,37 @@ The account specified in the `Account` field pays the transaction fee.
10711109
14. `PaymentTotal <= 0`. (`temINVALID`)
10721110
15. `PaymentInterval` is less than `60` seconds. (`temINVALID`)
10731111
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`)
10741113

10751114
##### 3.8.5.2 Protocol-Level Failures
10761115

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`)
1096-
20. `LoanBroker.CoverAvailable < (LoanBroker.DebtTotal + PrincipalRequested + InterestDue) × LoanBroker.CoverRateMinimum` (insufficient first-loss capital). (`tecINSUFFICIENT_FUNDS`)
1097-
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`)
1134+
19. `LoanBroker.CoverAvailable < (LoanBroker.DebtTotal + PrincipalRequested + InterestDue) × LoanBroker.CoverRateMinimum` (insufficient first-loss capital). (`tecINSUFFICIENT_FUNDS`)
1135+
20. The Borrower does not have sufficient reserve for the `Loan` object. (`tecINSUFFICIENT_RESERVE`)
1136+
21. The Borrower is not authorized for the asset. (`tecNO_AUTH`)
1137+
22. The `LoanBroker.Owner` is not authorized for the asset. (`tecNO_AUTH`)
1138+
23. The `LoanBroker.LoanSequence` has reached its maximum value. (`tecMAX_SEQUENCE_REACHED`)
1139+
1140+
24. `LoanBroker.lsfLoanBrokerPrivate` flag is set:
1141+
1. `LoanBroker.DomainID` is not set (LoanBroker is private, but domain is not configured). (`tecNO_AUTH`)
1142+
2. `Borrower` does not have credentials in the LoanBroker's `PermissionedDomain`. (`tecNO_AUTH` / `tecEXPIRED`)
11011143

11021144
#### 3.8.6 State Changes
11031145

0 commit comments

Comments
 (0)