All articles
Lending  ·  Data

Reading liquidation risk across two very different lending designs

Xora Labs Data  ·  10 min read

Ask “how much of this market is at risk of liquidation” across two lending protocols and you will get two numbers that look comparable and are not. The difficulty is not data collection. It is that pooled and isolated designs mean genuinely different things by the same words.

Two designs, one vocabulary

In a pooled design, users supply into shared reserves and borrow against a portfolio of collateral. Risk parameters are set per asset and governed centrally, and a user's health depends on their whole position at once. In an isolated design, each market is a separate pair with its own oracle, its own liquidation threshold and its own interest-rate model, permissionlessly created.

Both will report “utilisation”. In the pooled case it is a property of a shared reserve that every borrower draws on. In the isolated case it is a property of one pair that has no relationship to the pair next to it. Averaging across them produces a number with no referent.

Where naive normalisation goes wrong

  • Health factor is not portable. One protocol's 1.05 and another's 1.05 can imply very different distances to liquidation, because the thresholds and the assets they apply to differ.
  • Aggregate TVL hides concentration. A billion across forty isolated markets is not a billion in one pool. The tail risk lives in whether any single market is thin.
  • Bad debt means different things. In a pooled system it socialises across suppliers. In an isolated one it is contained to that market's suppliers, which is a design feature, not a smaller problem.
  • Oracles are per-market in isolated designs. Two markets on the same asset can disagree about its price, legitimately.

The schema that works

We stopped trying to produce one comparable number and instead made the unit of analysis the market, defined as the narrowest scope in which a liquidation decision is actually made. In a pooled protocol that is the reserve plus its parameter set; in an isolated protocol it is the pair. Every metric is computed at that level and is never averaged across levels without an explicit weighting the caller chooses.

On top of that, each market carries its risk context as data rather than as an assumption:

  • The oracle actually used, its source and its staleness
  • The liquidation threshold and penalty in force at that block
  • The interest-rate model and where on the curve utilisation currently sits
  • Whether losses socialise beyond this market, and to whom
If a metric cannot be defended without also stating which oracle produced it and which threshold applies, it should not be exposed as a single number.

Computing risk without pretending

The useful question is rarely “what is the average health factor”. It is “how much value gets liquidated if this asset falls by X”. That question is answerable per market without any cross-protocol normalisation at all, and it composes cleanly: run the shock per market, then sum the outcomes.

It also degrades honestly. If one market's oracle is stale, that market's contribution is flagged rather than silently included, which is the behaviour you want at exactly the moment the numbers matter most.

Why we build this internally

We built this to serve our own keepers and strategies, where being wrong is expensive and immediate. That constraint is what keeps the schema honest: nobody on the team is rewarded for a dashboard that looks tidy, only for one that does not lose money.

Working on something like this? Get in touch.