Skip to main content

Lend Midnight to Vault

LendMidnightToVaultCallback moves a lender out of a fixed-rate Midnight position and into an ERC-4626 vault. This can happen before maturity or after maturity.

Description

A lender holds a fixed-rate position on Morpho Midnight and wants to exit into a variable-rate vault, either before or after maturity. They post a sell (borrow) offer on Midnight to exit their lending position with this callback set as receiverIfMakerIsSeller. When the sell (borrow) offer fills, the callback receives the taker's payment and deposits it into an ERC-4626 compliant vault (typically a Morpho Vault-V2) on the lender's behalf.

Why an ERC-4626 vault, not Morpho Blue directly?

The simplest destination is a Morpho Vault-V2 that allocates 1:1 into a single Morpho Blue market: an unmanaged, immutable vault that mirrors one variable-rate market.

Targeting an ERC-4626 vault rather than a Morpho Blue market directly also keeps the callback generic: the same path supports the Money Market product, curated/managed vaults, and any third-party ERC-4626 strategy whose asset() matches the Midnight market's loan token.

Step-by-step callback execution

Before any take, the lender posts an exit sell (borrow) offer on the Midnight source market with receiverIfMakerIsSeller set to this callback. The offer carries the callback wiring; the take triggers it.

LendMidnightToVaultCallback flow: a taker calls take() on the lender's exit sell (borrow) offer on Midnight; the taker's payment (sellerAssets) lands on the callback, which deposits it into the ERC-4626 vault and mints shares to the lender.
  1. Take: A taker fills the lender's exit sell (borrow) offer on Midnight by calling MORPHO_MIDNIGHT.take(). The taker's payment (sellerAssets) lands on the callback because the offer's receiverIfMakerIsSeller points at it, and Morpho Midnight invokes onSell on the callback.
  2. Validate the target vault: The vault's asset() must equal the Midnight market's loanToken. Otherwise the callback reverts with TokenMismatch.
  3. Check the lender is debt-free on the source market: If the lender currently holds debt on the same Midnight market, the callback reverts with PositionCrossing. The lender must remain a pure lender throughout the exit.
  4. Calculate & transfer fee: A flat percentage fee is taken from sellerAssets; if non-zero, it is transferred to feeRecipient. When routed through the ratifier, the fee is forced to zero and this step is skipped.
  5. Deposit into the vault: Approve the vault and call deposit(sellerAssets - fee, seller). The lender receives the vault shares directly.

Example

A lender holds a fixed-rate lend position of 10,000 USDC on cbBTC/USDC · 30d (the source). They want to exit the fixed term and park the funds in USDC Vault-V2 at the variable rate.

  1. The lender posts an exit sell (borrow) offer for 10,000 USDC on cbBTC/USDC · 30d, with receiverIfMakerIsSeller set to LendMidnightToVaultCallback.
  2. A taker fills the offer. The taker's 10,000 USDC payment (sellerAssets) lands on the callback, and Midnight invokes onSell.
  3. The callback confirms USDC Vault-V2's asset() is USDC, and that the lender holds no debt on cbBTC/USDC · 30d.
  4. It calls deposit(10,000 USDC − fee, lender) on the vault.

The lender ends the take holding vUSDC shares worth ~10,000 USDC in USDC Vault-V2, with their fixed-rate position on cbBTC/USDC · 30d closed.

Prerequisites

  • The sell (borrow) offer's receiverIfMakerIsSeller must point at this callback so sellerAssets lands here before onSell fires.
  • The lender must not be carrying debt on the same Midnight market at execution time.
  • The target vault's underlying asset() must equal the Midnight market's loanToken.
Fees are capped at 0% through the ratifier

The callback supports fee configuration via feeRate, but the Migration Ratifier caps Midnight exit flow fees at 0%, effectively disabling fees on ratifier-managed migrations (MAX_FEE_RATE_FIXED_TO_VARIABLE = 0). Any non-zero setFeeConfig for these callbacks reverts at the ratifier.