Docs

Set up fallback rolling

Authorize and configure fallback rolling so a Midnight loan can move into a Morpho Blue market, then track rolls.

The contract-call snippets use an ABI compiled from the contract source; the SDK example is only for reading Morpho Blue market liquidity.

Fallback rolling contracts (BlueFallbackRolling) are listed on the Addresses page and contract specs are available here.

1. Find a matching Morpho Blue market

Choose a Morpho Blue market with the same loan token and collateral token as the Midnight position. The Midnight position must have exactly one active collateral; otherwise roll reverts with IncorrectActivatedCollateral. Confirm its actual available liquidity before enabling rolling. Available liquidity can change before roll is submitted.

REST API

GET https://api.morpho.org/v0/blue/markets/8453:<market_id>/liquidity

Read data.market_liquidity for liquidity already in the Morpho Blue market. data.reallocatable_liquidity is separate Public Allocator capacity; it does not count until reallocated into the market.

The REST API's market-selector uses <chain_id>:<market_id>.

SDK

import { fetchBlueMarket } from "@morpho-org/morpho-sdk/fetch";

const market = await fetchBlueMarket(marketId, publicClient);
const availableLiquidity = market.liquidity;

Onchain (direct contract read)

const [totalSupplyAssets, , totalBorrowAssets] = await publicClient.readContract({
  address: morphoBlueAddress,
  abi: morphoBlueAbi,
  functionName: "market",
  args: [marketId],
});
const availableLiquidity = totalSupplyAssets - totalBorrowAssets;

The Public Allocator can move additional liquidity into an eligible market, subject to participating vault settings and flow caps. A roll only counts liquidity already in the destination market when the transaction runs. See the Public Allocator overview for the distinction between market liquidity and reallocation capacity.

2. Authorize the contract

The borrower authorizes the fallback rolling contract on both Midnight and Morpho Blue.

Find the contract address on the Addresses page. Do not hardcode an address from another deployment.

await walletClient.writeContract({
  address: midnightAddress,
  abi: midnightAbi,
  functionName: "setIsAuthorized",
  args: [blueFallbackRollingAddress, true, borrower],
});
await walletClient.writeContract({
  address: morphoBlueAddress,
  abi: morphoBlueAbi,
  functionName: "setAuthorization",
  args: [blueFallbackRollingAddress, true],
});

An integrator contract the borrower has authorized on Midnight can call setConfig in the same transaction that opens the loan. From a wallet, your app can send the authorization and configuration calls as one batch with EIP-5792 wallet_sendCalls when the wallet supports it.

3. Set the rolling configuration

The borrower or an account they authorized on Midnight can set a configuration. It selects the Midnight position and Morpho Blue destination, sets a time window and incentive schedule, and can be enabled or disabled.

The configuration call has nine parameters:

ParameterMeaning
userBorrower whose Midnight position can be rolled.
midnightIdID of the Midnight market containing the debt.
blueIdID of the destination Morpho Blue market.
startFirst Unix timestamp when the configuration can be used.
endLast Unix timestamp when the configuration can be used; it must be later than start.
incentiveAtStartIncentive fraction at the start of the window, scaled by WAD.
incentiveAtEndIncentive fraction at the end of the window, scaled by WAD; it cannot be below the start value or above 100%.
minRollableAssetsMinimum debt amount for a partial roll, in loan-token units. Rolling all remaining debt is allowed below this amount.
enabledWhether this configuration can be used. Set it to false to disable it.
await walletClient.writeContract({
  address: blueFallbackRollingAddress,
  abi: blueFallbackRollingAbi,
  functionName: "setConfig",
  args: [
    borrower,
    midnightId,
    blueMarketId,
    start,
    end,
    incentiveAtStart,
    incentiveAtEnd,
    minRollableAssets,
    true,
  ],
});

The configuration ID is the hash of midnightId, blueId, start, end, incentiveAtStart, incentiveAtEnd, and minRollableAssets. The borrower address is the mapping key, and enabled is stored separately.

Example configuration

This two-window example was calibrated for one integration, with positions on Base and Ethereum and a deep BTC-backed Morpho Blue market. It is an example for that integration, not a default for other chains or markets. It uses two configurations for the same position, active one after the other.

ParameterWindow 1: liquid marketWindow 2: market with less available liquidity
startMaturity minus 13 hoursMaturity minus 12 hours
endMaturity minus 12 hoursMaturity
incentiveAtStart00
incentiveAtEndBase: 0.225 / position size in USD; Ethereum: 24.75 / position size in USD100 bps (1%)
minRollableAssets$1,000$1,000

The table gives dollar and percentage targets, not the raw values setConfig takes. Convert minRollableAssets to loan-token units with the token's decimals: for a loan token worth about $1 with 6 decimals, such as USDC, $1,000 is 1000n * 10n ** 6n. Convert incentives to WAD-scaled fractions, where 100% is 10n ** 18n: 1% is 10n ** 16n.

Both windows set the incentive as a fraction of the rolled debt, rising from 0 at start to incentiveAtEnd at end. In the first window, incentiveAtEnd is the roll caller's expected gas cost in dollars divided by the position size, so near the end of the window the incentive pays about that dollar amount. It needs updating when the position size changes. In the second window, incentiveAtEnd is 1% of the debt.

Keep configurations current

If the loan size or market conditions change, review the configuration. Disable a configuration that no longer applies by calling setConfig with its existing parameters and enabled = false. A changed parameter set has a different configuration ID, so enabling a replacement does not by itself disable the earlier one. Adding a second collateral to the Midnight position blocks rolling until only one collateral is active again. Both authorizations from step 2 apply to all of the borrower's positions on that protocol, not only the one being rolled. When no enabled configuration is needed anymore, revoke them by repeating the two calls with false.

Running a roller

Find positions to roll

A roller watches SetConfig events for enabled configurations, their windows and incentives, and the borrower's Midnight debt. It submits roll when a window is open and the Morpho Blue market has liquidity. A SetConfig event records the caller, borrower, source and destination market IDs, window, incentive values, minimum roll amount, and enabled state.

user is the borrower address from the SetConfig event, not the roller's own wallet. The market and configuration arguments (start, end, incentiveAtStart, incentiveAtEnd, minRollableAssets) must match an enabled configuration exactly, for example the values from its SetConfig event; otherwise the call reverts with NotConfigured. SetConfig gives the market IDs, not the market structs roll takes: get them with toMarket(midnightId) on Midnight and idToMarketParams(blueId) on Morpho Blue. For a full roll, pass the borrower's current Midnight debt, read just before submitting. If the position changes before the transaction runs, the call can revert and must be rebuilt with fresh values.

await walletClient.writeContract({
  address: blueFallbackRollingAddress,
  abi: blueFallbackRollingAbi,
  functionName: "roll",
  args: [
    midnightMarket,
    blueMarketParams,
    user,
    start,
    end,
    incentiveAtStart,
    incentiveAtEnd,
    minRollableAssets,
    assets,
  ],
});

Track rolls

EventInformation
RollCaller, borrower, source and destination market IDs, configuration ID, debt amount rolled in this call, collateral amount, and incentive amount.

GET /v0/midnight/users/{user-address}/transactions

Filter the user's transaction history with event_types=roll. Roll records use the TransactionRoll schema, which includes data.config_id.

For the contract reference, see Midnight periphery.

Post-roll support

After a roll, the borrower's loan is a Morpho Blue position. An integration that supports fallback rolling must also display Morpho Blue positions and support at least the Morpho Blue borrow actions, such as repaying and withdrawing collateral, so the borrower can keep managing the loan. See Get Data and Supply Collateral, Borrow, Repay & Withdraw Collateral.