> ## Documentation Index
> Fetch the complete documentation index at: https://ormaprotocol.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Four Worked Examples: Using Orma as an Investor or Lender

> Worked examples: comparing two facilities, pricing pledged vault shares, attracting rated capital, and gating deposits with XLS-70 credentials.

Every figure on this page comes from the live Orma API at ledger `5263343` (`2026-09-12T22:20:22Z`) against Devnet `rippled 3.4.0-rc5`. Nothing here is a projection. The two haircut figures in Use Case 2 are arithmetic performed on that reading rather than a captured response body, and the text says so where they appear.

The thesis all four cases share: the party who decides **when** a vault recognises a loss is the same party who decides **in what order** those losses are realised. The `LoanBroker` owner is necessarily the vault owner — a protocol fact, not a configuration choice. Both decisions move money from unit holders to that party. Orma measures both from public ledger state, publishes the result where it can be acted on, and lets an independent third party enforce it.

<Warning>
  All four facilities run on Devnet. XLS-65 (vaults) and XLS-66 (lending) are not live on Mainnet, so none of this points at a production facility today. XLS-70 (credentials) and XLS-80 (permissioned domains), which Use Case 4 is built from, **are** live on Mainnet; what keeps Use Case 4 Devnet-only is the vault underneath it. Every transaction hash below resolves on `devnet.xrpl.org`.
</Warning>

***

## Use Case 1: An LP Choosing Between Two Facilities

Two closed-ended XRP facilities, both in the Investment phase, both scored by the same code path with no weights applied anywhere.

|                       | Kestrel Bridge Financing II | Calder Structured Credit III |
| --------------------- | --------------------------- | ---------------------------- |
| `vaultId`             | `24EAA01A…E5810089`         | `5763707D…A96CB0E5`          |
| Vault grade           | **B** (26 / 100)            | **AA** (89 / 100)            |
| Conduct grade         | **E** (25 / 100)            | **A** (100 / 100)            |
| `assetsTotal`         | `10500000` drops            | `51000000` drops             |
| `lossUnrealized`      | `0`                         | `10000000` drops             |
| `navNaive`            | `0.210000`                  | `1.000000`                   |
| `navCorrect`          | `0.210000`                  | `0.803922`                   |
| `navDivergenceBps`    | **0**                       | **1961**                     |
| Defaults on record    | 2                           | 0                            |
| Impairments on record | 0                           | 1                            |

The two columns disagree in exactly the way that matters. Kestrel reports **zero** NAV divergence. Calder reports 19.61%. A screener that ranks by divergence puts Kestrel on top — Kestrel is the worse facility by a wide margin. The reason is mechanical: divergence only becomes non-zero once a manager has **declared** a loss. Kestrel's manager never declared one. They went straight to default, at which point the loss was realised, `LossUnrealized` never moved off zero, and the book read clean again. This is why `GET /api/vaults` sorts by `gradeNumeric` ascending and not by divergence.

### What Kestrel's manager actually did

Reconstructed from three transactions on the public record via `GET /api/vaults/:vaultId/broker-history`:

| Event           | Time      | Hash        | Principal  | `debtBefore` | Cover consumed |
| --------------- | --------- | ----------- | ---------- | ------------ | -------------- |
| `cover_deposit` | 21:08:32Z | `E979EB6D…` | `0`        | `0`          | `0`            |
| `default`       | 21:11:02Z | `FB23EC53…` | `30000000` | `40000000`   | `400000`       |
| `default`       | 21:11:10Z | `DE49DF0D…` | `10000000` | `10000000`   | `100000`       |

The 30 XRP loan was declared first, then the 10 XRP loan. Cover liquidated on a default is:

$T(p) = \min\Big(\big\lceil D \cdot c_{\min} \cdot c_{\text{liq}} \big\rceil,\; p,\; C\Big)$

where $D$ is the broker's **total** book, not the defaulting loan's principal, and $D$ decrements after each default. At $c_{\min} = c_{\text{liq}} = 10000$ (both in $10^{-5}$ units, so the effective coefficient is $0.10 \times 0.10 = 0.01$), the two possible orderings give:

| Order                         | Step 1   | Step 2   | Total cover consumed |
| ----------------------------- | -------- | -------- | -------------------- |
| Largest first (what happened) | `400000` | `100000` | **`500000`**         |
| Smallest first                | `400000` | `300000` | **`700000`**         |

The manager's own first-loss capital absorbed 0.50 XRP instead of 0.70 XRP. The 0.20 XRP difference did not disappear — it fell on the unit holders. The API reports this as `ordering.costToDepositors: "200000"` with `fairness: "0.0000"`, placing the sequence at the investor-worst end of the range.

Conduct score: 100, minus 35 for a sequence score below 0.25, minus 20 for each of two exposures written off with no prior impairment — giving **25 and a grade of E**.

### What Calder's manager actually did

One loan, 10 XRP, went past due. The manager impaired it (transaction `BD18EFB9…F52D5F4F`), which moved `LossUnrealized` from `0` to `10000000` and took the honest unit value from 1.000000 down to 0.803922. No default has been declared. The ordering rule requires two defaults before it applies, no exposure was written off without warning, and no first-loss capital has been withdrawn — nothing deducts from the starting 100, and the conduct grade is **A**.

The vault itself is graded **AA**, not AAA. The notch trace explains why:

```json theme={null}
"notchTrace": [
  { "from": "AAA", "rule": "anchor on DEADLINE (can claims be met at redemption)", "delta": 0, "to": "AAA" },
  { "from": "AAA", "rule": "single loan >= 75% of broker debt (cover is keyed to total debt, not loan size)", "delta": -1, "to": "AA+" },
  { "from": "AA+", "rule": "liquidatable cover < 5% of recognised loss", "delta": -1, "to": "AA" }
]
```

Both notches are about structure, not about disclosure. Disclosing the loss cost Calder 1961 bps on its published unit value and cost its conduct grade nothing.

### API calls

```bash theme={null}
# All tracked facilities, worst grade first
curl -s localhost:8787/api/vaults \
  | jq '.vaults[] | {label, grade, gradeNumeric, navDivergenceBps}'

# The manager's record, reconstructed from account_tx
curl -s localhost:8787/api/vaults/24EAA01AD4CE70D8ABB4ACB4255DC4C216B8AF3B9E7315DB8052BFC1E5810089/broker-history \
  | jq '{ordering, reputation}'
```

<Note>
  Conduct is reconstructed from `account_tx`, which Devnet retains for roughly 29 days. The API returns that caveat in the response body rather than burying it in a footnote. Conduct before the retention window is not visible, and Orma does not claim that it is.
</Note>

***

## Use Case 2: A Second Lender Pricing Pledged Shares

An LP holds units of Calder's share token and wants to borrow against them from a different broker. The units are escrowed on-ledger: XLS-85 `TokenEscrow` accepts MPT amounts, and vault shares are MPTs, so `EscrowCreate` with `Amount: { mpt_issuance_id, value }` returns `tesSUCCESS`. The pledge is then a public object. What it is worth is the open question.

The second broker starts from the only identifier they have — the issuance id — and runs the resolution loop. Every step is on the ledger, or on a URL the ledger itself names.

### Token metadata resolution

```bash theme={null}
curl -s "localhost:8787/api/mpt/000000014D667775372D5B78E07FFF294678C7F9CE82AFBC/resolve?units=1000000"
```

```json theme={null}
"steps": [
  { "step": "read MPTokenIssuance", "ok": true, "detail": "issuer r3hE8HanpccSZdgmeHCfYFEkwxFjdDmmvt, 51000000 units outstanding" },
  { "step": "decode metadata", "ok": true, "detail": "valid JSON" },
  { "step": "XLS-89 conformance", "ok": true, "detail": "asset_class rwa" },
  { "step": "find valuation pointer", "ok": true, "detail": "http://localhost:8787/api/mpt/000000014D667775372D5B78E07FFF294678C7F9CE82AFBC/nav" },
  { "step": "follow pointer", "ok": true, "detail": "unit value 0.803922" }
]
```

Nothing in that loop required the borrower's cooperation, and nothing required a relationship with Orma. The pointer template `http://localhost:8787/api/mpt/{mpt_issuance_id}/nav` was written into `MPTokenMetadata` at `VaultCreate`. The broker substitutes the token's own id and follows it.

### The valuation

A pledge of 1,000,000 units, priced both ways. Values are integer strings in the vault's asset base unit (drops for an XRP vault):

```json theme={null}
"pledge": {
  "units": "1000000",
  "valueHeld": "803922",
  "valueReported": "1000000",
  "overstatement": "196078"
}
```

In XRP: reported 1.000000, held 0.803922, **overstatement 0.196078, or 19.61%**. A lender who prices on the reported figure is over-collateralised on paper by 0.196078 XRP per 1,000,000 units — and short by that amount in reality.

### Why a haircut does not save you

A haircut applies to the **held** value, never to the reported one:

$V_{\text{lendable}} = V_{\text{held}} \cdot (1 - h)$

At $h = 0.20$ on this pledge, `maxLendable` is `643138` drops. A lender applying the same 20% to the reported value lends `800000` drops against collateral genuinely worth `803922`. They intended a 20% cushion. They have 3,922 drops of it — 0.49% of the true value. The haircut was consumed entirely by the misstatement before it absorbed a single tick of volatility.

### API calls

```bash theme={null}
# Value a specific pledge by issuance id
curl -s "localhost:8787/api/mpt/000000014D667775372D5B78E07FFF294678C7F9CE82AFBC/nav?units=1000000"

# Trace the full resolution chain step by step
curl -s "localhost:8787/api/mpt/000000014D667775372D5B78E07FFF294678C7F9CE82AFBC/resolve"

# A lender's own escrows, valued both ways, with haircut applied to the honest value
curl -s "localhost:8787/api/vaults/5763707D11EA19D1B5FF04E4EBA4F9336057955CDE65B725D1FF3EF2A96CB0E5/collateral?haircut=20&accounts=rEXAMPLE" \
  | jq '{navNaive, navCorrect, totalOverstatement, totalOverstatementPct, pledges}'
```

<Warning>
  No global index exists from an `mpt_issuance_id` to the escrows holding it. The `/collateral` route requires a list of accounts to scan. An escrow appears in the owner directory of both pledgor and beneficiary with the same object index, so a lender can enumerate pledges made in their own favour by scanning their own objects — which is the question that actually matters for lending. Orma deduplicates by index when the same escrow comes back more than once.
</Warning>

***

## Use Case 3: A Vault Owner Attracting Graded Capital

Being measured looks adversarial. It is not. The chain is short:

<Steps>
  <Step title="Write the pointer">
    The share token carries a pointer to an honest valuation, written once at `VaultCreate` into `MPTokenMetadata`.
  </Step>

  <Step title="Any counterparty can price the units">
    No cooperation from the holder, the manager, or Orma is required.
  </Step>

  <Step title="Priceable units are usable as collateral">
    A unit that cannot be independently valued is refused by a careful lender. One that can be valued is accepted.
  </Step>

  <Step title="Collateral-eligible units are worth more to hold">
    The facility raises capital from lenders who know what they are buying.
  </Step>

  <Step title="Cite Orma's issuer in a PermissionedDomain">
    Name `rKQjjU5KFs9RAZCDvYVjcaoVK5gGsCJgkP` in a `PermissionedDomainSet`. Orma signs nothing and cannot decline to be cited — the grade is Orma's opinion, and the domain is the owner's.
  </Step>
</Steps>

Calder's manager completed step 1 by writing 502 bytes of JSON into `MPTokenMetadata` at `VaultCreate`. Five XLS-89 fields so explorers will list the token, then one namespaced block that does the work:

```json theme={null}
"orma": {
  "v": 1,
  "instrument": "vault-share",
  "nav_url": "http://localhost:8787/api/mpt/{mpt_issuance_id}/nav",
  "nav_url_param": "{mpt_issuance_id}",
  "nav_basis": "assets net of recognised loss, divided by units outstanding",
  "doc": "https://orma.credit/nav"
}
```

<Warning>
  Share metadata is write-once, permanently. No transaction and no key can update it — including the manager's and including Orma's. That is why the field holds a **pointer** and never a number.
</Warning>

### The grade is an asset, not a threat

Calder's manager holds a conduct score of **100 / 100, grade A**, earned by impairing a loan rather than sitting on it. That grade has three properties an honest manager wants:

<CardGroup cols={3}>
  <Card title="Not self-reported" icon="fingerprint">
    It is rebuilt from transaction hashes anyone can fetch. A competitor cannot claim it, and the manager cannot be talked out of it.
  </Card>

  <Card title="Disclosure doesn't cost it" icon="shield-check">
    Realised capital destruction is measured against total assets, not net assets. Recognising a loss early cannot worsen your grade.
  </Card>

  <Card title="Passport to gated capital" icon="key">
    A grade A manager can reach allocators whose domain names Orma's issuer. A grade E manager cannot.
  </Card>
</CardGroup>

### API call

```bash theme={null}
# Verify your gate setup — checks the share issuance, not the Vault object
curl -s localhost:8787/api/vaults/<vaultId>/gate \
  | jq '{gated, issuerNamed, acceptedCredentials}'
```

***

## Use Case 4: An LP Checking Entry to Thorne Senior Secured I

Thorne Senior Secured I (`4A5A8E37…B00190DF5`) is verified end to end on Devnet. The setup requires four transactions; the deposit check requires two.

### Setup sequence

| Step | Transaction                                               | Result           | Hash        |
| ---- | --------------------------------------------------------- | ---------------- | ----------- |
| 1    | `CredentialCreate` — Orma issues `ORMA-IG` to an LP       | `tesSUCCESS`     | `619CC767…` |
| 2    | `CredentialAccept` — the LP opts in                       | `tesSUCCESS`     | `41F98989…` |
| 3    | `PermissionedDomainSet` — vault owner names Orma's issuer | `tesSUCCESS`     | `4C425830…` |
| 4    | `VaultCreate` with `tfVaultPrivate` and `DomainID`        | `tesSUCCESS`     | `3FC79BF7…` |
| 5    | `VaultDeposit`, LP with credential                        | `tesSUCCESS`     | `7FC5C01B…` |
| 6    | `VaultDeposit`, LP without credential                     | **`tecNO_AUTH`** | `E7CF5DB2…` |
| 7    | `CredentialDelete` — Orma revokes                         | `tesSUCCESS`     | `E2D6F396…` |
| 8    | `VaultDeposit` after revocation                           | **`tecNO_AUTH`** | `AA25246A…` |
| 9    | `VaultWithdraw` after revocation                          | `tesSUCCESS`     | `2E71A259…` |

Resulting state from `GET /api/vaults/4A5A8E37.../gate`:

```json theme={null}
{
  "gated": true,
  "private": true,
  "domainId": "FFBEC89D98B4E7CF52F4F254235086514A90CED0EC531941BDF747AF40C5A2FB",
  "acceptedCredentials": [
    { "issuer": "rKQjjU5KFs9RAZCDvYVjcaoVK5gGsCJgkP", "type": "ORMA-IG", "typeHex": "4F524D412D4947" }
  ],
  "domainOwner": "rGFFSqqY1R3764FKF7crU5F6bYh9qaD45S",
  "issuerNamed": true,
  "raterAddress": "rKQjjU5KFs9RAZCDvYVjcaoVK5gGsCJgkP"
}
```

### Why this is a rating and not a private arrangement

Step 3 is signed by the **vault owner alone**. Orma signs nothing, is not consulted, and cannot decline to be cited. `issuerNamed: true` in the response above is Orma answering a question about itself that it was never asked. That asymmetry is the difference between a rating and a bilateral deal — and it is how incumbent rating agencies work: an issuer references a rating, and the agency gets no veto over being referenced.

Step 2 is the mirror asymmetry. Issuance alone grants nothing. Without `CredentialAccept` the deposit is still `tecNO_AUTH`, so a credential cannot be done *to* someone.

<Note>
  Credentials are keyed to the **bar**, not to the facility. `ORMA-IG` means "may enter facilities graded BBB- or better" and is reusable across every vault that names Orma's issuer. One credential per facility would be a whitelist wearing a credential's clothes. `CredentialType` is a hex blob of 1 to 64 bytes; `ORMA-IG` serialises to `4F524D412D4947`.
</Note>

### Revocation is one-directional, on purpose

Steps 8 and 9 are the sharpest pair in the sequence. After `CredentialDelete`, the LP's next deposit bounces immediately and their existing position is untouched — they withdraw in full, `tesSUCCESS`. The gate controls who may **enter**, never who may leave. The alternative is a rater who can trap capital, which nobody should accept and which Orma does not implement.

<Warning>
  `DomainID` is **not** stored on the Vault ledger entry. It lives on the share `MPTokenIssuance`. Reading the Vault object to check whether a vault is gated returns nothing, which looks exactly like "open to everyone". Use `GET /api/vaults/:vaultId/gate` — it reads the issuance.

  `tfVaultPrivate` (`0x00010000`) is **required** alongside `DomainID` on `VaultCreate`. A `DomainID` without the flag gates nothing, and the API reports that case explicitly as `"carries a domain but is not flagged private, so nothing is enforced"`.
</Warning>

<Tip>
  Always read the **validated** ledger result, not `engine_result`. An `engine_result` of `tecNO_AUTH` can go on to validate as `tesSUCCESS`. On gate transactions specifically, reporting the provisional answer is the difference between "the ledger refused them" and "the ledger let them in".
</Tip>

### API call

```bash theme={null}
# Check gate status, accepted credentials, and whether Orma's issuer is cited
curl -s localhost:8787/api/vaults/<vaultId>/gate \
  | jq '{gated, acceptedCredentials, issuerNamed}'
```
