The problem: an empty change set
When a manager impairs a loan under cash-basis accounting (LEVersion = 1), only one field on the Vault ledger object changes: LossUnrealized moves from 0 to the impaired amount. AssetsTotal stays the same. AssetsAvailable stays the same. Units outstanding, which live on the share token’s MPTokenIssuance, stay the same.
Here is the Vault object for Meridian Trade Finance I before and after its impairment, in drops:
A naive reading divides assets by units:
The correct reading nets out the recognised loss first:
That is a gap of 1961 basis points between two readings of the same object at the same instant.
The impairment transaction is
075FE6D2E0F29919AF477A2A8F581A680805A006138BB967D8434611E49229C3, result tesSUCCESS. Its metadata for the Vault node reads:
rippled. It is correct metadata. It is also a silent wrong answer for every downstream consumer that builds vault state by applying deltas. Orma’s reader therefore never diffs PreviousFields. It polls a known list of vault IDs every 4,000 ms and re-reads each object in full.
One asymmetry, two levers
The impairment above was discretionary. Nothing in the protocol required the manager to declare it that day rather than a week later. During the Investment phase,VaultWithdraw returns tecTOO_SOON for the entire phase regardless of how much cash the vault holds, so an investor who suspects a problem cannot leave. That is lever one: when a loss is recognised.
Lever two is in what order losses are realised, and it moves real money. When a loan defaults, the cover the broker forfeits is sized against the broker’s total drawn debt at that moment, not against the principal of the loan that defaulted:
Because is decremented as each default lands, declaring a large exposure first shrinks the base for everything that follows. Total cover consumed across a fixed set of defaults therefore depends entirely on the order they are declared.
Kestrel Bridge Financing II had two loans — 30 XRP and 10 XRP — both of which defaulted. The manager declared the 30 XRP loan first:
Same two losses, same rates, same day — 0.20 XRP difference in what the manager’s own first-loss capital absorbed. That 0.20 XRP fell on unit holders. By the rearrangement inequality this is general: total first-loss capital consumed is always minimised by declaring the largest exposure first. See Mathematics for the full derivation and three independent proofs.
The party who chooses the order is the LoanBroker owner, who is necessarily the vault owner —
LoanBrokerSet returns tecNO_PERMISSION otherwise, and XLS-75 delegation is temMALFORMED for the entire lending suite. So the same account decides when a loss is recognised and in what order losses are realised, and both decisions move money from investors to them.
Orma’s three-step answer
Measure
Orma scores five factors independently on a 20-step ordinal ladder from AAA to D: liquidity, first-loss adequacy, concentration, recognition lag, and the redemption cliff. No weights are applied anywhere — a weighted average lets a strong factor pay for a broken one. The composite grade anchors on the redemption cliff and is notched down by rule. A separate conduct score assesses the manager rather than the book: the observed default sequence against its best and worst possible orders, plus penalties for losses written off without prior impairment. The key design choice is realised capital destruction, , measured against rather than . A write-off removes the asset fromAssetsTotal, releases the provision, and leaves the book reading clean. Without this term, a vault that lost 79% of subscribed capital would grade AAA — identical to one that never lost a penny. With it, Kestrel grades B.
Publish
The reading goes on-chain twice. First as a native XLS-47 Price Oracle: sixPriceData entries per vault, one per dimension — NAV, HDL, LIQ, COV, CNC, DDL. An Oracle is a native ledger object, and get_aggregate_price computes a median across independent publishers inside the ledger, so a second publisher who disagrees changes the aggregate without asking. Second, as a pointer inside the share token’s own XLS-89 metadata, under an orma key carrying a nav_url template, so a lender holding nothing but the MPT issuance ID can resolve to a valuation without knowing Orma exists.
See Mathematics — Publication as an Oracle Object and NAV Pointer for details.
Enforce
A grade nobody acts on is a press release. Orma issues an XLS-70 credential of typeORMA-IG to a limited partner. The LP accepts it (issuance alone grants nothing — a deposit without the accept is still tecNO_AUTH). A vault owner who wants graded capital names Orma’s issuer in a PermissionedDomain and creates the vault with tfVaultPrivate. After that, the ledger itself refuses a deposit from an uncredentialed account. Orma signs nothing in that step, is never asked, and cannot refuse to be cited.
Revocation is asymmetric on purpose: deleting the credential bounces the next deposit and leaves the existing position fully withdrawable. A rater who can trap capital is a worse problem than the one being solved.
See Gate for the full enforcement walkthrough.
The four live Devnet facilities
All four facilities are live on Devnet and readable by anyone pointed atwss://s.devnet.rippletest.net:51233 (network id 2). The reader loads all four at startup.
Where to go next
Concepts
Vault phases, the LoanBroker relationship, cash-basis accounting, and why the broker owner is always the vault owner.
Quickstart
Clone, prove the toolchain, start the reader, and call your first API endpoint.
Mathematics
Every formula Orma computes: NAV two ways, the cover formula, the ordering proof, the five scoring factors, and the oracle encoding.
Gate
Issue XLS-70 credentials, bind them to a permissioned domain, and enforce access at the ledger level.
NAV Pointer
Write a valuation pointer into share token metadata so any lender can price a pledge from the token ID alone.
Use Cases
Four worked cases against three live Devnet facilities, including collateral pricing and gate enforcement.