BaseMigrationRatifier
Git Source - Generated with forge doc
Inherits: Ownable2Step, IMigrationRatifier
Title: BaseMigrationRatifier
Abstract migration ratifier implementing callback discrimination, protocol fee config, and the window, cadence, and rate checks.
An entry point resolves the migrating user, their callback/callbackData, the migration offer,
and the declared (sourceTenorMarketId, targetTenorMarketId) route, then calls _ratify.
If the user holds an opposite-side position in the target Midnight market, Midnight nets the positions, which exits the netted position at the offer price, validated by the rate check.
offer.start, offer.expiry, offer.reduceOnly, offer.maxUnits and offer.maxAssets are not ratified, so that any offer satisfying the ratified constraints can settle the migration. Settlement-side guards (receiver pinning, reserved-group namespace) are supplied by the concrete entry point.
Renewals do not check source health: a liquidatable source position can still be renewed.
Fee config (setFeeConfig) is owner-only and takes effect immediately, no timelock; the user's rate check runs
after the fee, so it cannot weaken rate protection.
Constants
MORPHO_MIDNIGHT
The Morpho Midnight protocol the ratifier reads from.
IMidnight public immutable MORPHO_MIDNIGHT
BORROW_MIDNIGHT_RENEWAL_CALLBACK
address public immutable BORROW_MIDNIGHT_RENEWAL_CALLBACK
BORROW_BLUE_TO_MIDNIGHT_CALLBACK
address public immutable BORROW_BLUE_TO_MIDNIGHT_CALLBACK
LEND_VAULT_TO_MIDNIGHT_CALLBACK
address public immutable LEND_VAULT_TO_MIDNIGHT_CALLBACK
BORROW_MIDNIGHT_TO_BLUE_CALLBACK
address public immutable BORROW_MIDNIGHT_TO_BLUE_CALLBACK
LEND_MIDNIGHT_TO_VAULT_CALLBACK
address public immutable LEND_MIDNIGHT_TO_VAULT_CALLBACK
LEND_MIDNIGHT_RENEWAL_CALLBACK
address public immutable LEND_MIDNIGHT_RENEWAL_CALLBACK
State Variables
feeConfigs
mapping(address callback => mapping(bytes32 tenorMarketId => FeeConfig)) public feeConfigs
Functions
constructor
constructor(
address morphoMidnight,
address borrowMidnightRenewalCallback,
address borrowBlueToMidnightCallback,
address lendVaultToMidnightCallback,
address borrowMidnightToBlueCallback,
address lendMidnightToVaultCallback,
address lendMidnightRenewalCallback,
address _owner
) Ownable(_owner);
setFeeConfig
Sets the protocol fee config for (callback, tenorMarketId).
Only callable by the ratifier owner.
function setFeeConfig(address callback, bytes32 tenorMarketId, uint256 _feeRate, address _feeRecipient)
external
onlyOwner;
getEffectiveFeeConfig
Returns the effective fee config for (callback, tenorMarketId): the market-specific override if set (feeRecipient != address(0)), otherwise the action-level default keyed by tenorMarketId = bytes32(0).
function getEffectiveFeeConfig(address callback, bytes32 tenorMarketId)
public
view
returns (FeeConfig memory config);
_maxFeeRate
Max fee rate for callback: MAX_FEE_RATE_FIXED_TO_VARIABLE for Midnight exit flows, MAX_FEE_RATE
otherwise.
function _maxFeeRate(address callback) internal view returns (uint256);
_ratify
Runs the migration ratification flow for user against their resolved params, agnostic to make- or
take-on-behalf. user is the party whose position migrates; callback/callbackData are the migration
callback and its data on the user's side of the take; offer carries the migration market, tick (price), and
maker. src/tgt are the user-declared source/target Tenor market ids and must match the callback-derived
markets.
function _ratify(
address user,
address callback,
bytes memory callbackData,
Offer memory offer,
bytes32 src,
bytes32 tgt,
UserMigrationParams memory params
) internal view;
_validateMarketPair
Validates the declared source/target market pair against the markets derived from the callback, binding the user's params-key route to the callback's actual markets. Subclasses may override to enforce richer policy (e.g. a governance-curated set of allowed target markets for a given source).
function _validateMarketPair(
bytes32 sourceTenorMarketId,
bytes32 targetTenorMarketId,
bytes32 callbackSourceMarketId,
bytes32 callbackTargetMarketId
) internal view virtual;
_extractCallbackContext
Decodes callbackData for the given callback and returns the source and target
market context together with the callback's fee parameters.
A zero maturity marks the non-Midnight side of the migration (Blue or vault).
function _extractCallbackContext(address callback, bytes memory callbackData, Offer memory offer)
internal
view
returns (
bytes32 sourceTenorMarketId,
bytes32 targetTenorMarketId,
uint256 sourceMaturity,
uint256 targetMaturity,
uint256 feeRate,
address feeRecipient
);
_ratifyWindow
Checks that the take falls within the user's renewal window and that the target maturity is valid.
Variable sources (zero sourceMaturity, Blue or vault) have no maturity to renew around, so the window opens at the nearest past cadence boundary.
Fixed sources (Midnight) open the window renewalWindow seconds before sourceMaturity.
Returns the renewal period start passed to the interest rate policy.
function _ratifyWindow(UserMigrationParams memory params, uint256 sourceMaturity, uint256 targetMaturity)
internal
view
returns (uint256 renewalPeriodStart);
_validateTargetMaturity
Reverts unless targetMaturity is after sourceMaturity, within the user's duration bounds,
and on a cadence boundary when a cadence is set.
function _validateTargetMaturity(uint256 sourceMaturity, uint256 targetMaturity, UserMigrationParams memory params)
internal
view;
_ratifyRate
Checks the offer price against the policy rate and user's rate limit, net of settlement and protocol fees.
The settlement fee is borne by the taker, so it is netted only when offer.maker != user (none under
make-on-behalf). The check is continuous, while Midnight's integer settlement rounds against the taker.
function _ratifyRate(
address user,
address callback,
Offer memory offer,
UserMigrationParams memory params,
FeeConfig memory feeConfig,
bytes32 sourceTenorMarketId,
bytes32 targetTenorMarketId,
uint256 renewalPeriodStart,
uint256 sourceMaturity,
uint256 targetMaturity
) internal view;
_computeDuration
Returns the interest accrual duration used by the rate check for the given callback, by flow:
- Renewals (Midnight to Midnight):
targetMaturity - max(block.timestamp, sourceMaturity). Prices only the extension period; the source already pays interest until sourceMaturity. - Entries (Blue or vault to Midnight):
targetMaturity - block.timestamp. The full term of the new fixed-rate position;targetMaturity > block.timestampis already enforced in_validateTargetMaturity. - Exits (Midnight to Blue or vault):
sourceMaturity - block.timestamp. The remaining fixed term given up (zero at or after maturity).
When source funds become withdrawable before sourceMaturity (e.g. early repayments), a renewal relocks them until targetMaturity but only pays from sourceMaturity, so the lender's realized rate can fall below the ratified floor.
function _computeDuration(address callback, uint256 sourceMaturity, uint256 targetMaturity)
internal
view
returns (uint256);
_userIsBuy
Returns true when the user is on the buy side of the Midnight take for the given callback.
The user buys credit on Midnight when entering or renewing a lend position, or exiting a borrow position; the user sells when entering or renewing a borrow position, or exiting a lend position.
function _userIsBuy(address callback) internal view returns (bool);
_effectiveUnitsPerWad
Returns the per-WAD effective face value at maturity after Midnight's continuous fee on Midnight-target lend flows, and WAD otherwise.
Matches Midnight's fee model: the lifetime fee is fixed at take time as continuousFee * timeToMaturity and amortized linearly to maturity, so the lender nets units * (WAD - continuousFee * timeToMaturity) / WAD.
Worst-case assumption: the entire fill is treated as newly subject to the continuous fee (no netting against pre-existing debt); the realized rate with existing debt is strictly better than ratified.
function _effectiveUnitsPerWad(address callback, bytes32 marketId, Offer memory offer)
internal
view
returns (uint256);