Tenor Adapter
The Tenor Adapter enables batching Tenor and Morpho Midnight operations into a single atomic transaction through Morpho's Bundler3. It wraps Morpho Midnight operations, ratifier configuration, and Tenor Router batch execution into passthrough functions that maintain correct callback routing.
For example, a borrower initiating a new position can approve tokens, supply collateral, take a sell offer (a borrower's offer to borrow), and configure auto-renewal in a single transaction through the adapter. If any step fails, the entire bundle reverts and the borrower is back where they started.
The recommended way to construct these batches is via the Tenor SDK, which handles ABI encoding, authorization routing, and call ordering. Hand-rolling a Bundler3 multicall is supported but error-prone.
Bundle Composition
A Tenor bundle is a Bundler3.multicall composing calls across several adapters:
TenorAdapter: Tenor and Morpho Midnight operations (this page). It is not a single monolithic contract — it composes three base adapters, each contributing one slice of functionality:MidnightAdapterBase(Morpho Midnight operation wrappers and callback reentry),MigrationRatifierAdapterBase(renewal-parameter passthroughs for the Migration Ratifier, which it pins as an immutable at deploy time), andTenorRouterAdapterBase(sentinel resolution andexecuteAndConsumefor filling limit offers). It does not include authorization operations.AuthorizationAdapter: long-lived Morpho Midnight authorizations, on a separate contract fromTenorAdapter. See Authorization Adapter below.GeneralAdapter1: Morpho's standard adapter. Used for ERC-20transferFrom(with Permit2), native ETH wrap/unwrap, ERC-4626 vault deposits/withdrawals, and Morpho Blue operations.CoreAdapter: Morpho's base adapter thatGeneralAdapter1extends. Used for native ETH transfers and ERC-20 transfers from adapter balance.
Authorization grants (midnightSetIsAuthorized) are exposed by the AuthorizationAdapter, not by TenorAdapter. Token approvals and these grants are scoped to the adapters above (plus renewal callback contracts). They are never granted to Bundler3 itself: Bundler3 is a stateless dispatcher, and any approval it held would become available to every adapter routed through it.
Direct Morpho Blue supply / borrow / repay / withdraw are not exposed through the Tenor SDK. The Blue surface is touched indirectly: Blue↔Midnight migrations bridge via a GeneralAdapter1 flash loan, with the renewal callback contracts handling the Blue side internally.
Benefits of the Tenor Adapter
All Tenor operations go through the adapter rather than calling contracts directly, for two reasons.
- Callback routing. Bundler3 callbacks must come from the same address that was called. Passthrough functions ensure the adapter is
msg.senderto Tenor contracts, so callbacks flow back correctly. - Atomic execution. Multiple operations can be batched into a single transaction, with all-or-nothing execution.
Morpho Midnight Operations
The adapter exposes passthrough functions for core Morpho Midnight operations.
- midnightRepay: Repay debt. Pass
type(uint256).maxasassetsto repay using the adapter's full loan-token balance, or asdebtto repay the initiator's entire current debt. - midnightSupplyCollateral: Supply collateral from the adapter's balance. Supports
type(uint256).maxto use the adapter's full balance. - midnightWithdrawCollateral: Withdraw collateral on behalf of the initiator. Supports
type(uint256).maxto withdraw the initiator's full collateral. - midnightWithdraw: Withdraw loan assets from a market on behalf of the initiator. Supports
type(uint256).maxto withdraw the initiator's full credit after position update (slashing + continuous fee accrual). - midnightSetConsumed: Set the consumed amount for an offer group (used for atomic cancel + downstream action). Passing
type(uint256).maxcancels all offers in the group. - midnightFlashLoan: Execute a flash loan on Morpho Midnight.
Long-lived authorizations (granting other contracts access on Morpho Midnight) are handled by a separate adapter. See Authorization Adapter below.
Taking offers is done through the adapter's execute function (see Batch Take Execution below). The adapter does not expose a standalone midnightTake.
Ratifier Configuration
The adapter exposes passthrough functions for managing renewal parameters on the Migration Ratifier.
- migrationSetParams: Sets renewal parameters on behalf of the initiator.
- migrationClearParams: Clears renewal parameters.
These passthroughs ensure the adapter is msg.sender to the ratifier, so the adapter is the contract the initiator authorizes.
Batch Take Execution
The adapter's execute function batches multiple take actions in a single transaction. See Tenor Router for the full call signature, fill semantics, and per-batch invariants. The initiator (the original EOA) is resolved as the Midnight taker for every take action.
Callback Handling
The adapter implements callback interfaces that let it reenter Bundler3 from inside a Morpho Midnight operation. This is what enables batch operations (Bundler3.multicall) within a callback (e.g. supplying collateral, taking another offer, or repaying source debt as part of the same take).
- onBuy. Triggered when a buy (lend) offer is taken.
- onSell. Triggered when a sell (borrow) offer is taken.
- onRepay. Triggered during repay operations.
- onLiquidate. Triggered during liquidations.
- onFlashLoan. Triggered during flash loans.
All callbacks validate that msg.sender == MORPHO_MIDNIGHT, so only Morpho Midnight itself can invoke them. This prevents third parties from spoofing callbacks to manipulate the adapter's state.
Authorization Adapter
AuthorizationAdapter is a separate standalone Bundler3 adapter for granting or revoking long-lived authorizations from inside a bundle. Use it as part of a one-shot setup bundle so users don't need separate out-of-bundle approval transactions.
It exposes three passthroughs, all called on the initiator's behalf:
- midnightSetIsAuthorized: Authorize another contract on Morpho Midnight (e.g. a callback, the Tenor Adapter, or a ratifier such as the Migration Ratifier). Ratifiers reuse Midnight's native
isAuthorizedmap, so the same call is what opts a user into a ratifier. - setterRatifierSetIsRootRatified: Ratify (or un-ratify) an offer-tree root on a Midnight setter ratifier.
- ecrecoverRatifierCancelRoot: Cancel a previously-signed offer-tree root on a Midnight ecrecover ratifier.
A single Midnight setIsAuthorized grant gives the target contract the ability to act on every Midnight market the user has positions in, and to overwrite the user's renewal params on the ratifier (since the ratifier reuses Midnight's auth mapping). Only authorize contracts whose code you have audited and whose ABI you understand.