Skip to main content

Market Making Policy

The Market Making Policy lets a market maker quote a two-sided rate curve (lend and resell) to the Migration Ratifier.

Use Case

The policy is built for lend-side market making, round-tripping between a variable-rate market on Morpho Blue and a fixed-rate market on Midnight:

  1. Deposit funds into a Morpho Vault allocating to a Morpho Blue market, earning the variable rate.
  2. Lend fixed by migrating into a Midnight position when a borrower matches with the lend rate offered by the market maker.
  3. Resell the fixed position back into the variable-rate market when a third party wants to lend (or exit their borrow position) at the maker's exit rate, locking in the spread between entry and exit.

The maker quotes both legs continuously through one curve per market. The buy offer side prices lending into Midnight; the sell offer side prices exits out of lend positions.

The policy enforces that the buy (lend) rate is always at or above the sell (exit) rate at every maturity, ensuring non-negative spreads.

Yield Curve

Users can specify up to 8 points on their curve. For example, a curve might quote a lend rate of 4% for 1-day maturities, 5% for 1 week, 6% for 2 weeks, and so on.

Each point has three fields:

FieldMeaning
ttmTime to maturity, in seconds (the curve's x-axis)
sellRateExit rate quoted by the maker to exit a fixed-rate lend position
buyRateLend rate quoted by the maker to enter a fixed-rate position

The curve enforces that the lend rate is at or above the exit rate at every point. Equal rates (a zero spread) are allowed; the curve only reverts with CrossedCurve when sellRate exceeds buyRate.

The curve is managed via two functions:

  • setCurve(onBehalf, tenorMarketId, points) overwrites the entire curve.
  • clearCurve(onBehalf, tenorMarketId) removes it, after which quotes for that slot revert. This is the per-user kill switch.

Either function can be called by the curve owner directly, or by any address the owner has authorized on Morpho Midnight (the same authorization used for bundlers, no separate ACL).

Supported Directions

MarketMakingPolicy only supports entry (Blue/Vault → Midnight) and exit (Midnight → Blue/Vault) directions. It rejects Midnight-to-Midnight renewals, reverting with UnsupportedMidnightToMidnight.

Time to Maturity Interpolation

Unlike StaticRatePolicy (which interpolates on elapsed time since the renewal period start), MarketMakingPolicy interpolates on time-to-maturity (TTM): max(maturity - block.timestamp, 0). As maturity approaches, TTM decreases and the curve is read right-to-left.

Example: Three-Point Term Structure

A market maker quoting entries above exits at 7d / 30d / 90d on a Midnight market M:

Time to maturitySell rate (exit)Buy rate (entry)
7 days≈ 4% APR≈ 5% APR
30 days≈ 5% APR≈ 6% APR
90 days≈ 6% APR≈ 7% APR
8%7%6%5%4%3%7d30d90dTime to maturityRate (APR)5%6%7%4%5%6%Buy (entry, lend fixed)Sell (exit, resell)

The shaded area between the two lines is the spread the maker captures on each round trip. The policy enforces this gap stays non-negative at every maturity.

All three points are set in a single setCurve call. With this curve in place:

  • A lend exit on M maturing in 14 days reads sellRate interpolated between the 7-day and 30-day points.
  • A lend entry on M targeting a 60-day maturity reads buyRate interpolated between the 30-day and 90-day points.
  • A take further out than 90 days reads the 90-day rate flat.

Pausable Variant

PausableMarketMakingPolicy is a pausable subclass shipped alongside the base policy. When paused, getRate() reverts and blocks every take routed through any user's slot on that policy. The kill switch is global to the deployment, not per user.

  • Any designated pauser can call pause().
  • Only the owner can unpause().

The owner is not automatically a pauser. The owner must call setPauser(ownerAddress, true) to grant themselves pause ability. The owner can always unpause regardless of pauser status.