# Glossary

Every term the explorer uses, with its unit or scale and where it appears
(`table.column` in the indexed data, the page that shows it). Alphabetical.
Definitions are drawn from `architecture.md`, `contracts.md`, `decoder.md`,
the indexer schema (`apps/indexer/ponder.schema.ts`) and the shared package's
doc comments; where this repository does not define something, the entry says
so and points at the contract sources listed in `contracts.md` instead of
guessing.

Two conventions govern almost every number here: **1 unit = 1 smallest unit
of the loan token, due at settlement**, and **a price is a WAD (1e18 = par)**.

### Account tag (Coinbase)

Who an account is, learned from how it reaches Midnight. The one tag today is
`coinbase`: the TAKER of a take in a transaction sent to the ERC-4337
EntryPoint v0.6 (`0x5FF137D4…2789`, the same address on every chain) is a
Coinbase smart wallet, because Coinbase's integration puts each borrower behind
such a wallet. The tag is earned once and then sticks to the account on that
chain: every later action it takes, through whatever router, carries it, so a
Coinbase borrower's repay through Morpho's bundler is Coinbase flow. Only the
taker of a take earns it; no other event does. Router attribution reads it
after a Tenor router and before Morpho's (a tagged wallet using the Tenor app
is Tenor flow). **Appears in**: `account_tag` (one row per chain + account:
entry point, first take, take count), `accountTag` on every Midnight event
row (`take`, `repay`, `withdraw`, `collateral_event`, `liquidation`,
`activity`); the badge on `/address/{address}`; the "Coinbase" router on
`/activity` and `/tools/routers`.

### Address

A 20-byte EVM account, written lowercase with the `0x` prefix (40 hex). An
address is the same person on every chain, so `/address/{address}` spans the
whole registry and has no chain filter. **Appears in**: every `user`, `maker`,
`taker`, `caller`, `onBehalf`, `receiver`, `payer`, `sender`, `via` column;
`/address/{address}`; `/api/v1/address/{address}`.

### Announced market

A market a mempool broadcast has NAMED, whether or not it has been created
on-chain. A Midnight market is created lazily, at its first take, so roughly
half the market ids seen in the mempool have no `market` row — the offers for
them are the only record. Because a market id is the hash of its struct and
the indexer derives the id from the very struct the offer carries, the
announced facts are provably that market's own. **Appears in**:
`announced_market` (`chainId`, `marketId`, `loanToken`, `collateralTokens`,
`maturity`, first-seen block/time); the "Market not created onchain" badge on
`/market/{chainId}/{marketId}`, whose terms are recovered from
`mempool_offer.offerJson`.

### Bad debt

Debt a liquidation could not cover from the borrower's collateral: the
`badDebt` argument of a `Liquidate` event, in units. Bad debt is what moves a
market's `lossFactor` — the only thing that does — and lenders absorb it
lazily through `UpdatePosition`. **Scale**: units. **Appears in**:
`liquidation.badDebt`; the Liquidations table on market, address and
activity pages.

### Broadcast (mempool message)

One `Data(bytes)` event from the Mempool contract (`periphery/Log.sol` in the
Midnight repo): a pure broadcast channel whose fallback re-emits any call's
calldata, up to 1,000,000 bytes. Makers publish batches of offers this way;
the event's bytes are the wire blob described in `decoder.md` (a version byte,
a 4-byte gzip length, a gzip stream of `abi.encode((Offer, bytes
ratifierData)[])`, an optional ≤256-byte suffix). The decoder never throws: a
blob it cannot read is stored as `undecodable` with its raw bytes, and a later
decoder re-decodes all history on the next re-index. **Appears in**:
`mempool_message` (`sender`, `via`, `rawData`, `byteLength`, `decodeStatus`,
`decodeError`, `offerCount`, `hasLend` / `hasBorrow` / `hasRepay` /
`hasResell`), with one `mempool_offer` row per decoded offer; `/mempool`;
`/message/{chainId}/{eventId}`; `/api/v1/mempool/broadcasts`,
`/api/v1/broadcasts/{chainId}/{eventId}`.

### Buy / sell vs lend / borrow

Midnight's own vocabulary is **buy / sell**: an offer's `buy` flag says which
side of the take the MAKER is on. **Buyer = lender side, seller = borrower
side** — in a take the buyer gains credit (or burns their own debt) and the
seller gains debt (or burns their own credit); a user never holds credit and
debt at once in one market. The explorer labels offers by what the maker is
doing, combining `buy` with `reduceOnly`: buy + open = **lend** offer, buy +
reduce-only = **repay** offer (the maker may only burn their own debt), sell +
open = **borrow** offer, sell + reduce-only = **resell** offer (the maker may
only sell credit they already hold). Settled takes use a parallel vocabulary —
see *Take*. **Appears in**: `mempool_offer.buy`, `mempool_offer.reduceOnly`,
`take.offerIsBuy`; the "Type" column on `/mempool`, "Side" (and "Reduce
only") on the offer and broadcast pages.

### Callback

A contract an offer names to source settlement liquidity (`ICallbacks.sol`):
`offer.callback` plus opaque `offer.callbackData`, invoked when the offer is
filled so the maker's funds need not sit idle in Midnight. The zero address
means none. Morpho's `BlueBuyCallback` parks a maker's funds on Morpho Blue
and its `callbackData` is `abi.encode(MarketParams)` of the Blue market it
draws from (so `keccak256(callbackData)` is that Blue market's id); Tenor's
renewal and migration callbacks (Blue/Vault ↔ Midnight) are the addresses
Tenor offers name. In a take, `payer` / `receiver` is the callback when
liquidity flowed through one. **Appears in**: `mempool_offer.callback`,
`mempool_offer.callbackData`; `blue_buy_callback` (every callback the Morpho
factory deployed) and `blue_buy_callback_position` (what each holds per Blue
market); `/tools/blue-buy-callbacks`; the offer page.

### chainId

The EVM chain id. Every table's primary key starts with it, every query
filters by it and every chain-scoped URL carries it, because the same market
id, offer hash, transaction hash or vault address is only meaningful on its
chain (and the same ADDRESS can hold different contracts on different chains).
The registry: Base 8453, Ethereum 1, Arc 5042, Tempo 4217, Robinhood Chain
4663 (`packages/shared/src/chains.ts`; `/api/v1/chains`). **Appears in**:
every table; `/market/{chainId}/…`, `/markets/{chainId}/…`,
`/offer/{chainId}/…`, `/tx/{chainId}/…`, `/message/{chainId}/…`,
`/tools/vaults/{chainId}/…`.

### Collateral vault

A Tenor ERC-4626 vault whose SHARE token is an enabled collateral in Midnight
markets: borrowers post its shares. Each registered collateral vault's
address is therefore a `collateral_config.token` somewhere. The vault's
`asset()` is the pair's LOAN token, not its collateral (a share is a receipt
for a loan-token deposit into a Morpho variable market), which is why the
share is priced as assets-per-share × the underlying's
DeFiLlama price (`vault.totalAssets / vault.totalSupply`) — DeFiLlama does not
list the shares. A retired vault (superseded deployment) is still drawn on the
matured markets that used it but is neither snapshotted nor listed. **Appears
in**: `packages/shared/src/vaults.ts` (`kind: "collateral"`), `vault`,
`vault_snapshot`, `vault_holder`, `vault_event`; `/tools/vaults`,
`/tools/vaults/{chainId}/{address}`; `/api/v1/vaults`.

### Continuous fee

A market's per-second fee on lender credit: Midnight charges `credit ×
continuousFee × timeToMaturity / WAD`, with the time in seconds. The stored
rate is **WAD per second** (the on-chain field is a `uint32`); multiply by
31,536,000 (a 365-day year) to quote it as an annual rate — `1585489599` is
5.00%/yr. Copied from the loan token's defaults (`fee_default`) at market
creation. Fees accrue into a position's `pendingFee` and the market's
`continuousFeeCredit` (loan-token units). An offer's `continuousFeeCap` (same
scale) kills the offer if the market's fee rises above it. **Scale**: WAD/s.
**Appears in**: `market.continuousFee`, `market.continuousFeeCredit`,
`position.pendingFee`, `withdraw.pendingFeeDecrease`,
`mempool_offer.continuousFeeCap`, `fee_default.continuousFee`,
`liquidation.latestContinuousFeeCredit`; "Continuous fee" on the market page.

### enterGate / liquidatorGate

Two gate contract addresses in the Market struct, part of the market's
identity (both the Midnight market id and the Tenor market id hash them). Tenor
deploys gates from CREATE2 factories — `MidnightAllowlistGate` (per-user
credit / debt / liquidate rights), `DelayedLiquidationGate` (a grace period, a
liquidation period and a priority period, fixed at construction), and
`VaultV2AllowlistGate` for its vaults rather than markets — and the indexer
records each deployment and every allowlist change. Morpho's
`WhitelistEnterGateFactory` is labelled in the registry but not indexed.
What a gate enforces is defined by its contract (see the `gates/` directory
of tenor-contracts in `contracts.md`). **Appears in**: `market.enterGate`,
`market.liquidatorGate`; `tenor_deployment`, `tenor_contract_action`; "Enter
gate" / "Liquidator gate" on the market page; `/tools/midnight-gates`,
`/tools/liquidation-gates`, `/tools/vault-gates`.

### eventId

The indexer's (Ponder's) opaque id for one log — unique per chain, text, not
a hash. It keys every event table together with `chainId`, and it is the
segment of the broadcast page (`/message/{chainId}/{eventId}`), where it must
be URL-encoded. **Appears in**: `eventId` on `take`, `repay`, `withdraw`,
`collateral_event`, `liquidation`, `activity`, `mempool_message`,
`mempool_offer`, …; `/api/v1/broadcasts/{chainId}/{eventId}`.

### Group / consumed

`offer.group` is a 32-byte label a maker gives offers that share one budget,
and `consumed[maker][group]` is how much of that budget has been used, keyed
by (maker, group) GLOBALLY, not per market, so one group can span markets.
Every `Take` writes the new absolute value and the maker can raise it
directly with `SetConsumed` (absolute, monotone — never decreasing). An offer
is dead once `consumed` reaches its cap (`maxUnits` or `maxAssets`), which is
also how a maker cancels: consume the group. **Scale**: the cap's own
denomination — a take adds its `units` against a `maxUnits` offer, and the
maker's side of the assets (`buyerAssets` for a buy offer, `sellerAssets` for
a sell offer, loan-token smallest units) against a `maxAssets` offer
(Midnight.sol `take`). **Appears
in**: `take.group`, `take.consumed` (post-take absolute), `mempool_offer.group`,
`group_consumption` (the live value); the "consumed" offer status.

### Implied APR

The simple annual rate a zero-coupon price implies over the time left to
maturity — a display convention, the one the Midnight repo's own
`TickToPriceApr` script uses: `apr = (1e18 − price) / price / ttm ×
31536000`, with `ttm` in seconds. The same price is a higher APR the closer
the maturity; at a discount with no time left the rate is unbounded (the
explorer prints ∞ past 1000%), and a par price (tick 6744) is 0% at any
horizon. A RateRatifierV1 offer is different: its maker signed a per-second
simple-interest `signedRate`, so its APR is `signedRate × 31536000` at every
horizon. **Appears in**: the "APR" columns on `/mempool`, the offer, market
and take tables; `impliedAprPercent` / `offerAprPercent` in
`packages/shared`.

### Indexed through

The provenance stamp every Markdown twin, REST envelope and MCP result
carries: per chain, the block height (and its timestamp) the numbers are
current to — `Indexed through: Base block 48824989 (2026-10-27T21:46:12Z)` in
Markdown, `meta.indexed[]` in JSON. From the indexer's status when reachable,
otherwise the newest indexed event on the chain (an honest lower bound). A
chain with nothing indexed yet contributes no stamp.

### LIF (liquidation incentive)

The liquidator's incentive factor. After a market's maturity, liquidation of
any position still holding debt becomes UNCONDITIONAL (health no longer
matters) and the incentive ramps to its maximum over the following 60 minutes
— the ramp is on the incentive, never on eligibility, which opens AT the
maturity timestamp with no grace period. Before maturity, liquidation requires
the position to be unhealthy (see *LLTV*). The exact incentive formula lives
in `Midnight.sol` (see `contracts.md`), not in this repository. **Appears
in**: `liquidation.postMaturityMode` (which path was used); the pre- /
post-maturity mode column on `/risk`.

### Liquidation

A `Liquidate` event: a liquidator repays `repaidUnits` of a borrower's debt
and seizes `seizedAssets` of one collateral token; any shortfall is `badDebt`,
which moves the market's `lossFactor`. Two paths — unhealthy before maturity
(`maxDebt < debt`, see *LLTV*), unconditional after it (see *LIF*).
**Scale**: `repaidUnits` and `badDebt` in units, `seizedAssets` in the
collateral token's smallest units. **Appears in**: `liquidation` (`caller` =
the liquidator, `borrower`, `collateral`, `seizedAssets`, `repaidUnits`,
`badDebt`, `postMaturityMode`, `latestLossFactor`); `/activity`, `/risk`,
the market and address pages.

### liquidationCursor

A per-collateral, per-market parameter stored beside the LLTV in each
collateral config and shown with it as a percentage; the protocol enables
cursors through the `EnableLiquidationCursor` config event. Its role in the
liquidation path is defined in `Midnight.sol` (see `contracts.md`); this
repository stores and displays it only. **Scale**: WAD (1e18 = 100%).
**Appears in**: `collateral_config.liquidationCursor`; the collateral details
on the market page and the market-id decoder.

### LLTV

Liquidation loan-to-value: the fraction of a collateral's value that may be
borrowed against it before the position becomes liquidatable, set per
collateral per market. Health mirrors `Midnight.isHealthy` bit-for-bit
(`packages/shared/src/health.ts`): `maxDebt = Σ floor( floor(balance × price
/ 1e36) × lltv / 1e18 )` over the position's collaterals, and the position is
healthy while `maxDebt ≥ debt`, both divisions rounding down in that order. A
multi-collateral position has no single LLTV — `/risk` reports LTV (debt over
collateral value) against the position's blended liquidation line. **Scale**:
WAD (1e18 = 100%). **Appears in**: `collateral_config.lltv`,
`blue_buy_callback_position.lltv` (Morpho Blue's, same scale); `/risk`; the
market page's collateral details.

### lossFactor

The share of lender value a market has written off through bad-debt
liquidations. **Scale: `uint128.max` is 100% — NOT WAD** (2^128 − 1, so the
raw value is far beyond a double's precision; the indexer stores the event
value raw). It only moves on bad-debt liquidations, and lender losses are
applied lazily through `UpdatePosition`, which the contract emits before any
`Take` it affects in the same transaction. **Appears in**:
`market.lossFactor`, `liquidation.latestLossFactor`,
`market_change.lossFactorBefore/After`; "Loss factor" on the market page.

### Maker / taker

The **maker** signs an offer and publishes it (a broadcast); the **taker**
calls `Midnight.take` against it, choosing how many units to fill. Both are
recorded on the take, along with `caller` — the msg.sender INTO Midnight,
which is the router (Morpho's bundler, Tenor's adapter) when the taker went
through one, and the basis of router attribution (see *Via / router*).
**Appears in**: `take.maker`, `take.taker`, `take.caller`,
`mempool_offer.maker`, `mempool_offer.allowedTaker` (Price/RateRatifierV1
offers only: the one address allowed to take; null = anyone).

### marketId (Midnight market id)

The id of one Midnight market — one maturity. It is the full 32-byte
CREATE2 derivation of the SSTORE2 record the Midnight contract deploys at
market creation, whose runtime bytecode is `abi.encode(market)`:
`keccak256(0xff ‖ midnight ‖ uint256(0) ‖ keccak256(SSTORE2_PREFIX ‖
abi.encode(market)))`, `SSTORE2_PREFIX = 0x600b380380600b5f395ff3`. It equals
`Take.id_` and `MarketCreated.id_`, and its low 20 bytes ARE the record
contract's address, which is how the market-id decoder inverts it (one
`eth_getCode` + `abi.decode`, then re-hash to prove it). Reproduced by
`computeMarketId` in `packages/shared`. Lowercase hex. **Appears in**:
`market.marketId` and every `marketId` column; `/market/{chainId}/{marketId}`;
`/api/v1/markets/{chainId}/{marketId}`; the market-id decoder
(`/tools/market-id?id=`).

### Maturity

The settlement date of a market, a unix-seconds timestamp — not an event.
After it: no new debt (`take` reverts on a debt increase), liquidation of any
remaining debt is unconditional (see *LIF*), and lenders withdraw
first-come-first-served from `withdrawable`, which is funded only by
repayments and liquidations. Each Midnight market has exactly one maturity;
the maturity-agnostic family is the *Tenor market id*. **Scale**: unix
seconds. **Appears in**: `market.maturity`, `mempool_offer.maturity`,
`announced_market.maturity`; the maturity badge beside market ids.

### Morpho Blue market id

The OTHER 32-byte market id a Tenor user holds. Morpho Blue is the
variable-rate market Midnight positions enter from and exit to (through the
Blue ↔ Midnight callbacks), and its ids are a different scheme entirely:
`keccak256(abi.encode(loanToken, collateralToken, oracle, irm, lltv))` over
Blue's five-word `MarketParams`. Inverted from Blue's own `idToMarketParams`
index (then re-hashed to prove it), never from Midnight data. Blue is not
indexed here; it appears where a Midnight offer or roll names it. **Appears
in**: `blue_buy_callback_position.blueMarketId` (= `keccak256(callbackData)`),
`blue_rolling_action.blueMarketId`; `/tools/market-id?id=` decodes one;
`app.morpho.org/{chain}/variable/{id}` is its page.

### Offer

A maker's signed intent to lend or borrow, published off-chain through a
mempool broadcast and settled on-chain when a taker fills it. The struct
(`decoder.md`): the whole `market` (so an offer names its market's preimage,
not just its id), `buy`, `maker`, `start` and `expiry` (unix seconds; `start
= 0` is no constraint), `tick` (the price), `group`, `callback` +
`callbackData`, `receiverIfMakerIsSeller`, `ratifier`, `reduceOnly`,
`maxUnits` and `maxAssets` (exactly one is non-zero — the cap, in loan-token
smallest units) and `continuousFeeCap`. An offer dies by consumption
(`consumed[maker][group]` reaching the cap, through fills or `SetConsumed`),
by its expiry window, by ratifier de-authorization, or by the market's
continuous fee rising above its cap — nothing on-chain marks it dead, so the
explorer derives a status, first match wins: `consumed` (cap reached),
`expired` (expiry < now), `upcoming` (start > now), `filled` (some units
taken), else `open` (`offerStatus` in `packages/shared`). **Appears
in**: `mempool_offer` (one row per decoded offer), `offer_fill` (cumulative
fills per hash); `/offer/{chainId}/{offerHash}`; `/mempool`;
`/api/v1/mempool/offers`, `/api/v1/offers/{chainId}/{offerHash}`.

### offerHash

`keccak256(abi.encode(offer))` — the id of an offer, equal to the
`offerHash` argument of the `Take` that fills it, which is how broadcasts and
fills join. It is NOT the EIP-712 hash a ratifier signs (the Merkle leaf).
One caveat: a RateRatifierV1 maker signs a rate, not the tick, and the taker
replaces the tick at take time — since the tick is part of the hash, such a
take carries a hash its broadcast never had, so `offer_fill` never lines up
with a rate offer's broadcast (consumption, keyed by maker and group, still
does). Lowercase hex. **Appears in**: `mempool_offer.offerHash`,
`take.offerHash`, `offer_fill.offerHash`; `/offer/{chainId}/{offerHash}`.

### Open-term vault

A Tenor ERC-4626 vault holding the open-term (variable-rate) leg lenders
deposit into for a pair; it never appears inside Midnight itself. Registered
beside the pair's collateral vault in `packages/shared/src/vaults.ts` (`kind:
"openTerm"`), snapshotted hourly like it. Some pairs are lend-only (an
open-term vault with no collateral vault), where the market takes the
collateral asset directly. **Appears in**: `vault`, `vault_snapshot`,
`vault_holder`, `vault_event`; `/tools/vaults`; `/api/v1/vaults`.

### Oracle price

A collateral oracle's `price()`: the value of one collateral token in LOAN
token, scaled by `ORACLE_PRICE_SCALE = 1e36`, with BOTH tokens' decimals
already folded in. That is why health math needs no decimals and why
collateral never needs a USD price of its own — the oracle, not DeFiLlama,
says what collateral is worth, including vault shares DeFiLlama cannot price.
Oracles are per collateral per market (`collateral_config.oracle`); Tenor's
`OracleWithValidation` wraps a primary feed and checks it against a second
within `maxOracleDeviation` (WAD). Read live in the browser for `/risk` and
`/tools/oracle`, never indexed. **Scale**: loan per collateral × 1e36.

### Position (credit / debt / pendingFee)

A user's standing in one market: `credit` is units owed TO them at maturity
(the lender side), `debt` is units they owe at maturity (the borrower side),
`pendingFee` is continuous fee accrued against the credit — a user never
holds credit and debt at once in one market. What a lender paid for their
credit is not indexed, so there is no accrued-interest figure. Collateral
posted against the debt is a separate row per token. Useful invariant:
`market.totalUnits == Σ position.debt + market.withdrawable`. **Scale**:
units. **Appears in**: `position`, `position_collateral.balance`
(collateral-token smallest units), `position_change` /
`collateral_change` (before/after per write, the `/tx` state diff); `/users`,
`/risk`, `/address/{address}`.

### Price (WAD)

The zero-coupon price a take executes at: how much the buyer pays NOW, in
loan-token smallest units, per unit due at maturity — `assets ≈ units × price
/ 1e18`, rounded against the taker (Midnight.sol `take`). A non-zero
settlement fee is the gap between `buyerAssets` and `sellerAssets`, borne by
the taker; the continuous fee accrues separately, in `pendingFee`.
**Scale**: WAD, 1e18 = par (1.0); a discounted loan is always < 1e18. Where
the broadcast offer is known its exact `priceWad` is used; otherwise a take's
price is recovered as `buyerAssets × 1e18 / units` (exact to within
1/units). **Appears in**: `mempool_offer.priceWad` (null for RateRatifierV1
offers); derived on every take row; the "Price" columns.

### Ratifier

The contract an offer names in `offer.ratifier` to validate it at take time,
with `ratifierData` the taker forwards verbatim from the broadcast. Morpho's
`EcrecoverRatifier` and `SetterRatifier` ratify Merkle trees of offers
(leaf-wise EIP-712 — the ratifier's hash is not `offerHash`);
`PriceRatifierV1` adds an `allowedTaker`; `RateRatifierV1` has the maker sign
a per-second simple-interest `rate` (WAD/s) instead of the tick, which the
taker then picks (see *offerHash*). Tenor's `MigrationRatifier` is a per-user
renewal / migration policy store: `setParams` / `clearParams` (keyed by a
callback and a source → target *Tenor market id* — equal on a renewal in
place; `limitRatePerSecond` WAD/s, `renewalWindow`, `minDuration`,
`maxDuration` in seconds, a cadence contract such as `FourWeekCadence`),
`setFeeConfig`, ownership. Ratifier de-authorization is one way an offer
dies. **Appears in**: `mempool_offer.ratifier`, `mempool_offer.signedRate`,
`mempool_offer.allowedTaker`; `ratifier_action` (every MigrationRatifier
event; `user` is whose policy moved, `sender` the tx sender);
`/tools/ratifier`, `/tools/rate-policy`; the Renewal column on market pages.

### rcfThreshold

A loan-token-denominated threshold in the Market struct, and so part of both
the Midnight market id and the Tenor market id (a different threshold is a
different market). The explorer shows it as a token amount without a USD
figure: it is a protocol setting, not money the market holds. What "RCF"
stands for and how the threshold is applied is defined in `Midnight.sol` (see
the source pointers in `contracts.md`); this repository stores and displays
the value only. **Scale**: loan-token smallest units. **Appears in**:
`market.rcfThreshold`; "RCF threshold" on the market, Tenor-market and
market-id-decoder pages.

### reduceOnly

An offer flag: the offer may only SHRINK the maker's existing position, never
open a new one. With `buy` it yields the four offer kinds (see *Buy / sell vs
lend / borrow*): a reduce-only buy is a **repay** offer (the maker burns their
own debt), a reduce-only sell is a **resell** offer (the maker sells credit
they hold). **Appears in**: `mempool_offer.reduceOnly`.

### Settlement fee

A fee charged at settlement as a share of units, as a function of the time to
maturity at the moment of the take: a piecewise-linear schedule over seven
breakpoints at 0, 1, 7, 30, 90, 180 and 360 days, linear between them, flat
beyond 360 days, with the 0-day value applying post-maturity (Midnight.sol's
SETTLEMENT FEES NatSpec). Copied from the loan token's defaults at market
creation. **Scale**: the contract stores centi-basis-points (`cbp`, a
`uint16`; 1 cbp = 1e-6 WAD = 0.0001%) but its fee events emit the WAD value
itself, which the indexer stores as is (a market seeded from contract state
instead is scaled from cbp by 1e12) — seven WAD fractions as decimal strings
either way. **Appears in**:
`market.settlementFeeCbps`, `fee_default.settlementFeeCbps`; "Settlement fee"
on the market page (`0–7d 0.01% · 30–360d 0.05%` style).

### Take

A fill: one `Take` event, the only operation where units and assets differ
(`assets ≈ units × price / 1e18`, rounded against the taker; everywhere else — repay, withdraw,
liquidate — one unit is one asset). Buyer = lender side, seller = borrower
side. Because a take first cancels whatever a side already holds on the
opposite leg (the buyer burns their own debt before accruing credit; the
seller sells the credit they hold before taking on debt), the indexer stores
four per-side splits — `buyerCreditIncrease`, `buyerDebtDecrease`,
`sellerCreditDecrease`, `sellerDebtIncrease`, each pair summing to `units` —
and classifies the take from them: **new borrow** (buyer gains credit, seller
gains debt), **credit resale** (a lender exits by selling credit on), **debt
transfer** (a borrower buys back debt; someone else takes it on), **unwind**
(both sides net out), **mixed** (a fill crossing a boundary). `consumed` is
the post-take absolute `consumed[maker][group]`. **Scale**: units; assets in
loan-token smallest units. **Appears in**: `take`, `offer_fill`,
`group_consumption`; `/activity`, `/tx/{chainId}/{hash}`, the market, offer
and address pages.

### Tenor market id

The renewal-stable identity of a market in the maturity-less sense:
`keccak256(abi.encode(chainId, midnight, loanToken, collateralParams,
rcfThreshold, enterGate, liquidatorGate))` — the Market struct minus
`maturity` (`TenorMarketIdLib.sol` in tenor-contracts). Many Midnight markets
(one per maturity) share one Tenor market, and a Tenor market id commits to
its chain. Reproduced by `computeTenorMarketId` in `packages/shared`; the
explorer groups markets by it client-side (`useTenorMarkets`). The
MigrationRatifier's source / target ids are Tenor market ids, so one policy
row governs every maturity. Lowercase hex, 64 digits — indistinguishable from
a Midnight market id by shape; the resolver tells them apart by lookup.
**Appears in**: computed from `market` + `collateral_config`;
`ratifier_action.sourceTenorMarketId` / `targetTenorMarketId` /
`feeTenorMarketId`; `/markets/{chainId}/{tenorMarketId}`;
`/api/v1/tenor-markets`; "Market id without maturity" on the market page.

### Tick

An integer encoding a zero-coupon PRICE, not a rate: `price(tick) = 1e18 / (1
+ 1.005^(3372 − tick))`, WAD, rounded to a 1e11 step, increasing in tick; tick
3372 is a price of 0.5, tick 6744 (`MAX_TICK`) is par. Ticks must be
multiples of the market's `tickSpacing` (default 4). Prices come from the
on-chain lookup table (`TickLib.sol`, vendored bit-for-bit as
`packages/shared/src/ticks-table.ts`) — the table is authoritative; never
recompute the exponential. A RateRatifierV1 offer's tick is unsigned filler
the taker replaces (its price is null; `signedRate` prices it). **Appears
in**: `mempool_offer.tick`, `mempool_offer.priceWad`, `market.tickSpacing`.

### Time to maturity (ttm)

`maturity − now`, in seconds: the horizon an implied APR annualizes a price
over, and the input to the settlement-fee schedule. A fixed price implies a
rate that climbs without bound as ttm → 0, which is why an offer taken at the
brink of maturity shows ∞. **Scale**: seconds (days on the fee schedule's
breakpoints). **Appears in**: derived wherever an APR or a settlement fee is
shown; never stored (the maturity badge shows the date, not the ttm).

### totalUnits

Units outstanding in a market: `market.totalUnits == Σ position.debt +
market.withdrawable`. A Tenor market's total is the sum over its maturities;
"borrowed" / outstanding debt is `totalUnits − withdrawable` (floored at
zero). **Scale**: units. **Appears in**: `market.totalUnits`,
`take.totalUnitsDelta`, `market_change.totalUnitsBefore/After`; the market
and Tenor-market pages, `/markets`.

### Unit

**1 unit = 1 zero-coupon obligation = 1 smallest unit of the market's loan
token, due at settlement.** Every protocol quantity — credit, debt,
totalUnits, withdrawable, an offer's `maxUnits`, a liquidation's
`repaidUnits` — counts in units, so a borrower's total is what they owe at
maturity and a lender's is face value at maturity. Units and assets are 1:1
everywhere except `take`, where a price < 1 applies and the discount IS the
interest. Rendered with the loan token's decimals and symbol; in JSON a unit
count is a decimal string (it overflows a double). **Appears in**: every
`units` / `credit` / `debt` / `totalUnits` / `withdrawable` column.

### Vault market id

A Tenor market id that names a vault-wrapped Tenor market WITHOUT hashing:
the vault's address packed into the high 20 bytes over 12 zero bytes —
`bytes32(uint256(uint160(vault)) << 96)` (`TenorMarketIdLib.vaultToTenorMarketId`).
The migration ratifier keys vault lend routes this way. It commits to no
chain, so the vault registry supplies one; the shape is the test (a hashed id
ends in twelve zero bytes with probability 2^-96), and `bytes32(0)` is refused
— it is the ratifier's default-fee key. **Appears in**:
`ratifier_action.sourceTenorMarketId` / `targetTenorMarketId` for vault
routes; the search box and `/go` send one to `/tools/vaults/{chainId}/{vault}`
when exactly one live registered vault matches, else to `/tools/market-id`.

### Via / router

Router attribution: whose app a Midnight call came through. Every `activity`
row stores `via` — the event's `caller` argument (the msg.sender into
Midnight) when the event has one, else the transaction's `to` — and the
explorer labels it **Morpho** (`MidnightBundlesV1` / `V2`, called directly by
users), **Tenor** (`TenorAdapter` inside a `Bundler3.multicall`,
`MidnightTakeAndRepay`, and Bundler3 itself on the chains Tenor runs on),
**Coinbase** (by *account tag*, not by contract), or **direct** (EOAs, Safes,
the core contracts themselves). A handful of one-off transactions are
attributed by hash (`ROUTED_TRANSACTIONS`). Ladder: hash, then a Tenor router,
then the account tag, then Morpho's router. The raw address is stored, so a
new router is a registry row, not a re-index. **Appears in**: `activity.via`,
`mempool_message.via`, `take.caller` and the other `caller` columns;
`/activity`'s router filter; `/tools/routers`.

### WAD

Fixed-point with 18 decimals: 1e18 represents 1.0 (100%). Prices,
LLTVs, liquidation cursors, oracle deviation caps and Blue incentive shares
are WADs; per-second rates (continuous fee, signed rate) are WAD per second;
oracle prices are 1e36-scaled; `lossFactor` is the one scale that is NOT WAD
(`uint128.max`). **Appears in**: `priceWad`, `lltv`, `liquidationCursor`,
`continuousFee`, `signedRate`, `maxOracleDeviation`, `incentiveAtStart/End`.

### Withdrawable

Units in a market that lenders can withdraw now — funded only by repayments
and liquidations (a take moves no money into it). Before maturity a lender
exits by reselling credit; after maturity, withdrawals are
first-come-first-served from this pool, so it is the live measure of what has
been settled. **Scale**: units. **Appears in**: `market.withdrawable`,
`market_change.withdrawableBefore/After`; "Withdrawable" on the market page;
`withdraw` rows are the draws against it.
