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>/liquidityRead 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:
| Parameter | Meaning |
|---|---|
user | Borrower whose Midnight position can be rolled. |
midnightId | ID of the Midnight market containing the debt. |
blueId | ID of the destination Morpho Blue market. |
start | First Unix timestamp when the configuration can be used. |
end | Last Unix timestamp when the configuration can be used; it must be later than start. |
incentiveAtStart | Incentive fraction at the start of the window, scaled by WAD. |
incentiveAtEnd | Incentive fraction at the end of the window, scaled by WAD; it cannot be below the start value or above 100%. |
minRollableAssets | Minimum debt amount for a partial roll, in loan-token units. Rolling all remaining debt is allowed below this amount. |
enabled | Whether 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.
| Parameter | Window 1: liquid market | Window 2: market with less available liquidity |
|---|---|---|
start | Maturity minus 13 hours | Maturity minus 12 hours |
end | Maturity minus 12 hours | Maturity |
incentiveAtStart | 0 | 0 |
incentiveAtEnd | Base: 0.225 / position size in USD; Ethereum: 24.75 / position size in USD | 100 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
| Event | Information |
|---|---|
Roll | Caller, 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.
Borrow at a fixed rate
Build a Midnight borrower flow that finds markets, quotes an offer, authorizes the transaction, and borrows at a fixed rate.
Redeem lend at maturity
Redeem Midnight credit at maturity for the loan token, using SDK or raw contract flows to read the position and complete settlement.