Ladder · FX treasury

Ladder architecture

Thin orchestration on top of Morpho + Tenor — one Midnight position, a share ledger per entity.

Design principle

Write as little as possible. Morpho Blue, Midnight, Vault V2 and Tenor routing / callbacks / ratifier / oracle / gates already exist and are audited. Ladder = series state machine + per-entity pro-rata accounting on top.

End-to-end flow

Ladder (custom) Morpho (existing) Tenor (existing)
Group entity
Treasury deposits USDC
From that legal entity’s book, during the window
Ladder · core
SeriesVault
Mints entity shares · NAV-based pro-rata · enforces state machine
Morpho · existing
Vault V2 (ERC-4626)
Pooled USDC earns variable Blue yield while waiting for a match
Ladder · orchestrator
SeriesMatcher
Posts lend offer via Tenor · triggers Vault→Midnight callback on fill
Morpho · existing
Midnight position
Fixed-rate, fixed-term loan · SeriesVault is the sole lender of record
EarlyExitHandler Per-entity early exit via unit sale
SeriesRatifierAdapter Auto-renewal at maturity (thin Tenor wrapper)
SeriesVault redeem() Pull-based pro-rata payout at maturity

Series state machine

SUBSCRIPTION_OPEN → POOLING_CLOSED → MATCHED_ACTIVE → MATURED_SETTLED

Branches: PARTIALLY_MATCHED · UNMATCHED_TIMEOUT — withdraw blocked during pooling/match; early exit is a separate path.

Two accounting layers (keep separate)

Layer 1 · What Midnight sees

One lender, one address, one position. Midnight has no visibility into which group entity owns which share.

SeriesVault = lender of record
Layer 2 · What SeriesVault tracks

Share-token accounting inside SeriesVault. Each legal entity holds series shares = its claim on the pooled FX float.

5 entities → 1 Midnight position
Shares at deposit (NAV-based, fair within subscription window)
shares = deposit amount ÷ current NAV per share
Redemption at maturity (pull-based, ERC-4626 style)
payout = (entity shares ÷ total shares) × total settled amount

Contracts to write

1
SeriesVaultCore · most new work
  • Subscription window · mint series shares (NAV-based)
  • Deposit pooled USDC into Morpho Vault V2 on close
  • State transitions · block normal withdraw when matched
  • Pro-rata redemption at maturity · partial/timeout splits
2
SeriesMatcherMost complex policy logic
  • Post lend offer at target rate/term when pooling closes
  • Detect fills via TenorRouter · trigger Vault→Midnight migration
  • Report match results back to SeriesVault
  • Timeout · re-offer or cancel per product policy
3
SeriesRatifierAdapterThin wrapper
  • Series-level auto-renewal rules → Tenor Ratifier / IntentSettler interface
4
EarlyExitHandler
  • Pro-rata credit-unit sale before maturity
  • Expose estimated exit proceeds vs fixed rate to maturity separately
5
SeriesRegistry / FactoryAdministrative
  • Deploy series · track active/past for frontend discovery

Do not build (reuse existing)

Morpho Blue / Midnight / Vault V2 core
TenorRouter · TenorAdapter · migration callbacks
Base Ratifier / IntentSettler framework
Oracles (Tenor Oracle with Validation)
Liquidation logic (Morpho/Midnight)
Gate/allowlist (Tenor Vault V2 Allowlist Gate)

At maturity

1
Loan settles → lump sum to SeriesVault Keeper flips state to MATURED_SETTLED (automatic detection).
2
Path A — auto-renewal Route share into next fixed rung via ratifier — no redeem.
3
Path B — pull-based redeem() Each entity claims USDC · shares burned · isolated txs.
4
Path C — reinvest to Vault V2 Opt-in · keep series shares · pool vault.deposit() → BUFFER_ACTIVE · variable APY.
5
Optional: sponsored keeper Feels automatic to the desk; still one tx per entity (no push loop).
Never push-pay every entity in one loop — unbounded gas + one bad address blocks the whole group.

Security (non-negotiable)

  • Independent audit before real capital
  • Formal verification on pro-rata accounting invariant
  • Prove: Σ entity claims = total pool value
  • Bug bounty scaled to TVL
  • Capped pilot series first (small size, short term)

Audit surface = orchestration + accounting — not lending/liquidation core.

Why Ladder exists

Morpho Blue rates are mechanically volatile (utilization-driven IRM curve). An FX treasury cannot put a floating headline on cash that has to be there for a payout. Ladder pools that pre-positioned float in Vault V2, locks a fixed rate on a real Midnight match, and keeps each entity’s share so the group can still report Singapore separately from the UK.