> For the complete documentation index, see [llms.txt](https://docs.efficientdex.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.efficientdex.com/how-pools-work/hooks.md).

# Hooks

The three required and two optional hooks of an Efficient pool, and what the pool checks on every fill: fee bounds, price band and loan-to-loan swaps.

**An Efficient pool's hooks price its fills, and the pool checks every fill against its limits.** No hook can change those limits. These checks hold whichever hooks a pool runs, because every pool the factory creates runs the same pool code.

The pool itself has no curve. Its three required hooks set its liquidity curve, its fee logic and how any anchor moves. [The pool and its book](/how-pools-work/the-pool-and-its-book.md) covers how a fill that passes the pool's checks settles.

Two more hooks are optional: a controller hook and a loan-to-loan swap hook. The controller hook orders a pool's lending markets for certain operations, when the pool has more than one.

The loan-to-loan swap hook prices swaps between two loan assets. A loan asset is a token the pool can borrow. The first one is the other side of the pool's pair: USDC, in an Efficient pool that trades BTC against USDC.

Everlong vaults run the Everlong hook. It can also fill a swap on its leverage curve, and the pool checks and settles that fill exactly like any other. See [The Everlong strategy](https://docs.foreverlong.io/everlong/everlong-strategy). Other invariant hooks needn't quote leverage at all. [Build a hook](/run-a-pool/build-a-hook.md) explains how a pool operator writes one.

## The hook set

A pool's hooks are the five fields of its `HookSet`: three required hooks and two optional ones.

| Hook                   | Field            | What it decides                                                                                         | Required |
| ---------------------- | ---------------- | ------------------------------------------------------------------------------------------------------- | -------- |
| Invariant hook         | `invariantHook`  | The liquidity curve that prices each fill: spot price, preview and committed fill                       | Yes      |
| Fee hook               | `feeHook`        | The fee on each fill, returned inside the fill                                                          | Yes      |
| Recentring hook        | `recenterHook`   | How price observations fold in and how the anchor moves                                                 | Yes      |
| Controller hook        | `controllerHook` | The order of the pool's lending markets for certain operations, plus custody maintenance and recentring | No       |
| Loan-to-loan swap hook | `loanSwapHook`   | The price of a swap between two loan assets                                                             | No       |

The first Everlong vault runs the Everlong hook in all three required roles. It leaves both optional slots empty.

The pool checks each hook's code and identity at creation and at both ends of a hook change. It refuses a failing set with `HookInvalid`. [Build a hook](/run-a-pool/build-a-hook.md) covers those checks and which contracts can fill each role.

### Changing hooks

Only the pool operator schedules a new hook set. The pool operator or the guardian can cancel it. A scheduled set waits out the governance delay, which is 10 days in the first Everlong vault. The pool operator executes it only while the pool is paused.

A new set waits at least 10 days while a pool's band ceiling allows no price band. The same applies while a ceiling raise to allow no band is scheduled.

Executing a set that changes the invariant hook also clears feature bit 5, `FEATURE_LEVERAGE`. The Everlong hook needs that bit before it quotes leverage. [Roles and governance](/run-a-pool/roles-and-governance.md) gives each step.

## The required hooks

**The invariant hook prices every fill.** The pool asks it once per swap for the fill and its fee together. A swap calls the hook's `executeExactIn`. The pool's preview calls `previewExactIn` without committing. See [Trade](/use-efficient/trade.md).

Each request carries:

* the pool's book
* the direction
* the input
* the fee bounds
* an output ceiling
* one checked feed price, in a pool with a price band

[Build a hook](/run-a-pool/build-a-hook.md) details each item. A buy's input stops at the first loan asset's per-swap cap. The trader keeps any input the fill doesn't use.

The hook returns the input it used, the gross output, the fee it keeps and the fee rate. It also reports its spot price and curve coordinate after the fill.

The pool pays the gross output less the fee. It never alters a committed fill. A fill reverts with `FillInvalid` if it uses none of the input, uses more than the input, or pays nothing after the fee. A fill that pays out past the output ceiling reverts with `OutputAboveCeiling`.

### If a hook reverts

A hook that reverts takes the swap with it, and the trader sees the hook's own error. Deposits, exits and the pool's net asset value never call a hook, so they don't depend on one. The same holds for collateral top-ups in a pool that borrows.

### Observations and the anchor

The pool passes price observations to the recentring hook through two pool calls, `poke` and `recenter`. Both stop while the pool is paused. A swap makes neither call, though a hook may fold in the checked price a request carries.

Anyone can call the pool's `poke`. It passes the feed's price to the hook's `observe`. The call reverts with `PokeMove` if the hook's spot price moves by over 1%. It also reverts with `PokeMove` if the spot price ends further from the feed price than before and over 3% away.

The keeper, the pool operator or the controller hook recentres the pool through its `recenter(minAnchorN36, maxAnchorN36, deadline)`. That call runs the hook's `recenter`. It reverts after its deadline. It also reverts with `AnchorOutOfBounds` if the hook moves the anchor outside the caller's two bounds.

A pool with no price band reads no feed price, so its `poke` reverts with `NoBand`. Its anchor moves only through `recenter`. In such a pool, `recenter` passes the hook no price and holds the anchor to the caller's bounds alone.

## What the pool enforces on every fill

**A pool refuses any fill whose fee rate sits outside its floor and cap.** This holds whichever hooks it runs. A pool with a price band also refuses a fill whose price strays outside that band around the feed price. Either check reverts the whole swap. [Trade](/use-efficient/trade.md) lists the other limits on a swap.

### Fee floor and cap

A `feeWad` below the floor or above the cap reverts the swap with `FeeOutOfBounds`. The pool doesn't check the fee kept, `feeOut`, against that rate. It checks only that some output is left after the fee.

The floor is the higher of the pool-wide floor and the first loan asset's floor. The cap is the pool-wide cap. A hook that would quote above the cap must clip its rate and compute the fill on the clipped rate. The Everlong hook does this with its curve fee.

The pool operator sets the pool-wide floor and cap with `setFeeBounds`, and each loan asset's floor with `setLoanConfig`. The guardian can't change the pool-wide bounds. It can only raise a loan asset's floor.

The pool-wide floor can't exceed the cap. The cap can't exceed 100% or its committed ceiling, and can't fall below any loan asset's floor. `setLoanConfig` refuses a loan asset's floor above the cap.

The cap's ceiling starts at the cap the pool is born with. The pool operator moves it with `setBandAndFeeCeilings`. A cut applies at once, and a raise waits out the governance delay. The guardian can only cancel a scheduled raise.

The first Everlong vault's floor is zero and its cap is 10%. [Fees](/use-efficient/fees.md) covers what the fee pays and where it goes.

### The price band

**A pool with a price band refuses any fill outside the band around its feed price.** No hook can fill at an arbitrary price. The feed price is the pool asset's price in the first loan asset. It's derived from the two assets' USD prices. See [Price feeds and oracles](/how-pools-work/price-feeds-and-oracles.md).

The pool values the trader's input and the output after the fee at the feed price. It reverts with `PriceBand` if the two differ by more than the band either way. So the band covers the fee as well.

Each loan asset has its own band. `setLoanConfig` changes it, or `setRiskLimits` for the first loan asset. The guardian can only narrow a band. A band in force can't be zero, and the code caps it at 10%. The first Everlong vault's band is 8%.

No band can exceed the pool's committed band ceiling. That ceiling starts at the band the pool is born with. It moves the same way as the fee cap's ceiling, except that a raise waits at least 10 days.

**A pool can also run with no price band.** Its swaps and flows then read no price. A pool born with a zero band has none. The pool operator can drop a band later with `setMarketBand`.

In such a pool, the invariant hook prices every fill without a feed price. So it must declare `HOOK_CAP_UNPRICED`. The pool checks this at creation, when the band is dropped and when a new hook set executes. It doesn't check when a set is scheduled. A hook that doesn't declare it fails with `HookInvalid`.

To drop a band, the pool must have no debt, borrowing switched off and a single loan asset. The band ceiling must first rise to allow no band. The pool operator or the guardian can attach a band again at once.

## The optional hooks

### The controller hook

A controller hook can make the pool's `setPriorities`, `maintain` and `recenter` calls, just as the keeper and the pool operator can. It prices nothing.

`setPriorities` orders a pool's lending markets, when it has more than one. The financing router uses that order for borrowing, supply, withdrawals and repayments. `maintain` runs collateral top-ups, releases and refinancing in a pool that borrows. In a pool that lends, it runs supply migration.

No controller hook has shipped, so the keeper or the pool operator sets the lending-market order. See [Just-in-time financing](/how-pools-work/just-in-time-financing.md).

### Loan-to-loan swaps

**A pool can hold up to 16 loan assets, but `swap` trades the pool asset only against the first.** Any other pair reverts with `InvalidPair`. A pool with no price band holds only one loan asset.

Other loan assets trade through `swapLoan(assetIn, assetOut, amountIn, minOut, to, deadline)`. That call needs the optional loan-to-loan swap hook. The pool's `swapLoan` path is built and in audit. Each pool adds the hook that prices `swapLoan` at deployment, or later through a new hook set. No loan-to-loan swap hook has shipped yet. A pool with an empty slot reverts every `swapLoan` call with `LoanSwapDisabled`.

Once installed, the hook prices the swap. It returns the input it takes and the output the pool pays. The pool sets no price of its own, charges no fee and applies no fee floor or cap.

The pool still checks the hook's answer:

* The price must sit within the tighter of the two loan assets' bands, around the cross of their USD prices. Otherwise the swap reverts with `PriceBand`.
* Both USD prices must be within the pool's maximum price age, or the swap reverts with `StalePair`. See [Price feeds and oracles](/how-pools-work/price-feeds-and-oracles.md).
* The output can't exceed what the pool holds on hand of the output asset plus what the financing router can fund. It also can't exceed the output asset's per-swap cap. An input over the input asset's per-swap cap reverts with `NotionalCap`.
* The committed answer must match the hook's preview, or the swap reverts with `FillMismatch`.
* Afterwards, the pool's credit check must hold. In a pool that borrows, that check keeps net borrowing within the LTV pin. [Credit and collateral](/how-pools-work/credit-and-collateral.md) covers it.

A loan-to-loan swap also stops during a pause or while either loan asset is off peg. It stops too while feature bit 6, `FEATURE_LOAN_SWAP`, is clear. The first Everlong vault has one loan asset and bit 6 clear. [Just-in-time financing](/how-pools-work/just-in-time-financing.md) covers adding loan assets.
