Skip to main content
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.
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.

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. 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: The 30 XRP loan was declared first, then the 10 XRP loan. Cover liquidated on a default is: T(p)=min(Dcmincliq,  p,  C)T(p) = \min\Big(\big\lceil D \cdot c_{\min} \cdot c_{\text{liq}} \big\rceil,\; p,\; C\Big) where DD is the broker’s total book, not the defaulting loan’s principal, and DD decrements after each default. At cmin=cliq=10000c_{\min} = c_{\text{liq}} = 10000 (both in 10510^{-5} units, so the effective coefficient is 0.10×0.10=0.010.10 \times 0.10 = 0.01), the two possible orderings give: 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:
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

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.

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

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):
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: Vlendable=Vheld(1h)V_{\text{lendable}} = V_{\text{held}} \cdot (1 - h) At h=0.20h = 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

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.

Use Case 3: A Vault Owner Attracting Graded Capital

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

Write the pointer

The share token carries a pointer to an honest valuation, written once at VaultCreate into MPTokenMetadata.
2

Any counterparty can price the units

No cooperation from the holder, the manager, or Orma is required.
3

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.
4

Collateral-eligible units are worth more to hold

The facility raises capital from lenders who know what they are buying.
5

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.
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:
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.

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:

Not self-reported

It is rebuilt from transaction hashes anyone can fetch. A competitor cannot claim it, and the manager cannot be talked out of it.

Disclosure doesn't cost it

Realised capital destruction is measured against total assets, not net assets. Recognising a loss early cannot worsen your grade.

Passport to gated capital

A grade A manager can reach allocators whose domain names Orma’s issuer. A grade E manager cannot.

API call


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

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

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

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.
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".
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”.

API call