> 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/integrate/swaps-for-aggregators-and-solvers.md).

# Swaps for aggregators and solvers

How aggregators and solvers quote and fill swaps on Efficient pools. Covers the pool's swap call, PoolSwapAdapter, the Tycho adapter, the lens, price observations and the Swap event.

**Aggregators, solvers and routers fill against an Efficient pool through one of three entries:**

* The pool's own `swap`
* `PoolSwapAdapter`
* The Tycho adapter

All three trade the pool asset against the first loan asset. The first loan asset is the other token in the pool's pair, which the pool can borrow. In an Efficient pool that trades BTC against USDC, it's USDC. All three take exact input only, and every fill passes the same pool checks.

[Integrate](/integrate.md#choose-a-route) covers how to find pools, read their bindings and choose between the three entries. [Trade](/use-efficient/trade.md) sets out the swap call's parameters, limits, preview and common reverts.

Solvers that fill requests for pool shares use the entry market instead. See [Deposits and exits for apps](/integrate/deposits-and-exits-for-apps.md).

## Read-only lens

**The lens reads any pool's state and quotes without changing anything.** Its price-dependent calls return `ok` as false instead of reverting. So a quoting service or monitor can keep reading a pool while its feed is down.

| Call                                                         | What it returns                                                                                                                                                                                                                                                                              |
| ------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `identity(pool)`                                             | The pool asset, first loan asset, financing router, price feed, authority contract, deposit allowlist and factory. The `HookSet`: three required and two optional hooks. The pool operator, guardian, keeper, fee receiver and protocol fee receiver                                         |
| `facts(pool)`                                                | The pool asset on hand, and posted as collateral in a pool that borrows. The first loan asset held as the execution buffer, supplied and owed. The share supply, and whether the pool is paused                                                                                              |
| `config(pool)`                                               | The LTV pin and credit setting, with their bounds, step and cooldown. The pool's limits and fees. The first loan asset's per-swap cap, price band and reserve target. The committed ceilings on the price band and fee cap, with any scheduled raise. Any scheduled rise in the protocol fee |
| `price(pool)`                                                | The pool asset's feed price in the first loan asset, when it was observed and whether that loan asset is on its peg, with `ok`                                                                                                                                                               |
| `nav(pool)`                                                  | The same price fields, plus the pool's net asset value in the pool asset, with `ok`                                                                                                                                                                                                          |
| `loans(pool)`                                                | For each loan asset: its price band, fee floor, per-swap cap and reserve target. The pool's execution buffer in it, and how much of it the pool has supplied and owes. Its price and peg check                                                                                               |
| `venues(pool)`                                               | For each lending market the pool has admitted (nothing in a pool with none): the financing router's record of it, any collateral posted there, its supply and debt, the liquidity it can lend now, and its health. A retired market returns only its id and its `retired` flag               |
| `previewSwap(pool, poolAssetIn, amountIn)`                   | The pool's swap preview with `ok`: the input used, the output after the fee and the fee rate                                                                                                                                                                                                 |
| `levState(pool)` and `levQuote(pool, poolAssetIn, amountIn)` | Everlong vaults only: frame CR at the mark and at the feed price, each side's top of book, and the leverage fill for one swap with whether it beats the curve's fill                                                                                                                         |

The pool's own `hookContext()` and `swapContext(poolAssetIn, amountIn)` return what the pool would hand its invariant hook for a swap now. Unlike the lens, `hookContext()` reverts when a swap couldn't be priced: a stale feed pair, a sequencer outage or an unchecked price it needs. `swapContext` also reverts when the pool refuses the swap before its fill, such as a sell while paused or a zero input. [Trade](/use-efficient/trade.md#reads-before-a-swap) lists these cases.

**On an Everlong vault with leverage on, every quote is the better of the curve's fill and the leverage fill.** So offchain models price both. Katana's vault ships with `FEATURE_LEVERAGE` clear, so its hook never arms and every swap there fills on the curve. See [Deployments](/reference/deployments.md#katana).

`levQuote` gives the leverage fill on its own. [The Everlong strategy](https://docs.foreverlong.io/everlong/everlong-strategy) gives its maths. Both leverage calls treat the pool's invariant hook as the Everlong hook, so they work only on pools that run it.

## Swapping directly through the pool

**The pool's own `swap` is the base entry, and both adapters call it.** It pulls only the input the fill uses and makes no callback. See [Trade](/use-efficient/trade.md#the-swap-call) for the call.

After a partial fill, the allowance a settlement contract gave the pool still covers the unused input. `PoolSwapAdapter` clears its allowance to the pool after every call.

## PoolSwapAdapter

**`PoolSwapAdapter` is an exact-input entry over one pool's `swap`.** It checks the pool's report against the balances it measures. Each deployment serves one pool and trades its pool asset against its first loan asset, in either direction.

```solidity
function swapExactIn(
    address tokenIn,
    address tokenOut,
    uint256 amountIn,
    uint256 minOut,
    address to,
    uint256 deadline
) external returns (uint256 amountInUsed, uint256 amountOut);
```

The caller first approves the adapter for `amountIn`. Then `swapExactIn` runs four steps:

1. It checks the pair, that `to` isn't the adapter and that `amountIn` is above zero. A failed check reverts with `BadPair`, `BadRecipient` or `ZeroAmount`.
2. It pulls `amountIn` from the caller and approves the pool for it. It calls the pool's `swap` with the caller's `minOut`, `to` and `deadline`, then clears the approval.
3. It checks that the input leaving the adapter equals `amountInUsed`, that the output meets `minOut` and that `to` gained at least `amountOut`. Otherwise it reverts with `Misreport`.
4. It sends any unused input back to the caller.

## Aggregator routes

[**Integrate**](/integrate.md#choose-a-route) **lists the aggregators Efficient is integrated with.** This page covers two routes. One is an adapter for PropellerHeads' Tycho over every factory pool. The other is a KyberSwap source that quotes the first Everlong vault. The Tycho adapter is built, and a listing of the pools on Tycho is planned.

### Tycho adapter

**The Tycho adapter implements Tycho's swap adapter interface.** It serves every pool the factory has created. Once Tycho lists the pools, each platform built on Tycho decides for itself whether to route trades through it.

Three rules set the adapter's scope:

* A pool id is a factory pool's address, right-aligned in 32 bytes. Every call that reads a pool reverts with `UnknownPool` on any other id. `getCapabilities` returns the same answer for every id.
* It trades the pool asset against the first loan asset in either direction. Any other pair reverts with `BadPair`.
* It takes only sell orders, which fix the input, because the pool has no exact-output swap. A buy order reverts with `UnsupportedSide`.

| Function                                                   | What it returns                                                                                                                                          |
| ---------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `getPoolIds(offset, limit)`                                | A page of factory pools as 32-byte ids                                                                                                                   |
| `getTokens(poolId)`                                        | The pool asset and the first loan asset                                                                                                                  |
| `getCapabilities(poolId, sellToken, buyToken)`             | Sell orders, a price function and marginal prices                                                                                                        |
| `price(poolId, sellToken, buyToken, specifiedAmounts)`     | Each amount's average fill price after the fee: output over input used, in raw units. A zero amount asks for the marginal price, measured with the probe |
| `getLimits(poolId, sellToken, buyToken)`                   | The largest input the pool would fill now, funding included, and its output. Zeros when the pool can't quote                                             |
| `swap(poolId, sellToken, buyToken, side, specifiedAmount)` | The output, the gas used and the marginal price after the fill, measured with the probe. It doesn't return the input used                                |

Every function that takes a pool id accepts it only as `bytes32`. A `price` call reverts if the pool refuses to quote any one of its amounts.

**The probe is the larger of two amounts of the sell token, capped at 2^96 base units.** One is 1,000,000 base units. The other is about a dollar's worth of the token at the pool's feed. In the first Everlong vault, that's 0.01 cbBTC when selling cbBTC and about 1 USDC when selling USDC.

`getLimits` starts at the probe and doubles the input with each preview. It stops at the first input the pool fills only in part, or at 2^96 base units. It returns that fill as the limit. If the pool refuses an input, the adapter narrows the gap to within about 0.1%. It then returns the largest fill the pool accepted.

On an Everlong vault, selling the pool asset at the limit can fill as a lever-up on the leverage curve. The fill can then revert in funding. That happens when a lending market's cash is less than a lever-up fill's payout. See [Trade](/use-efficient/trade.md#the-preview).

`swap` pulls `specifiedAmount` from the caller and sells it to the pool, with the current block as its deadline. It sends the output and any unused input back to the caller. The caller measures that refund to find the input used. `swap` sets no minimum output, so the contract that calls it checks the output itself.

{% hint style="warning" %}
Both adapters work by approve and call. Nobody can recover tokens sent straight to either adapter, the sender included, even within the same transaction as the swap.
{% endhint %}

### KyberSwap

KyberSwap's DEX library includes an Everlong liquidity source. It quotes the first Everlong vault.

## The Swap event

**Each swap emits one `Swap` event from the pool, whichever entry called it and whichever curve filled it.**

| Field                       | Meaning                                                                                                                   |
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `sender`, `to`              | The calling address and the recipient, both indexed                                                                       |
| `poolAssetIn`               | `true` for a sell, `false` for a buy                                                                                      |
| `amountInUsed`, `amountOut` | The input taken and the output paid after the fee, in each token's base units                                             |
| `feeOut`                    | The fee, in the output token's base units                                                                                 |
| `feeWad`                    | The fee rate as a fraction of the gross output, with 18 decimals                                                          |
| `spotAfterN36`              | The invariant hook's price after the fill, in the loan asset per base unit of the pool asset, with 36 decimals            |
| `grossOut`                  | The output before the fee, in the hook's units: the loan asset with 18 decimals on a sell, pool-asset base units on a buy |
| `xAfter`                    | The curve's coordinate after the fill, with 18 decimals                                                                   |

**On a leverage fill, `feeWad` is the spread rate of its first unit.** `feeOut` is the spread the vault kept. `spotAfterN36` and `xAfter` keep their values from before the fill. That's because a leverage fill moves neither the curve's price nor its coordinate.

`feeOut` is zero on a lever-down filled wholly at the down cap's price. So `feeWad` times `grossOut` isn't the vault's revenue.

The Everlong hook emits `Levered(virtualLeg, crBeforeWad, crAfterWad)` before the pool settles a leverage fill. So settlement's transfers can fall between it and the `Swap`. A curve fill emits no hook event.

The hook's own `Observed(observedAt, referenceWad, emaWad, rvWad)` comes only from a `poke` or a `recenter`, never from a swap. Its fields differ from the pool's `Observed(referenceN36, observedAt)`.

[Smart contracts](/reference/smart-contracts.md) lists every other event.

## Price observations

**Anyone can call `poke`, which passes the feed's latest price to the pool's recentring hook.** It takes no arguments.

```solidity
function poke() external;
```

On the Everlong hook, a reading with a new value updates the smoothed feed price and the volatility figure its fee reads. The hook ignores a reading it has already taken in, and a poke doesn't move the anchor.

The pool runs no observation on a swap, and the Everlong hook never takes in a price during one. Its curve prices on the last reading that a `poke` or a `recenter` passed it. See [The Everlong strategy](https://docs.foreverlong.io/everlong/everlong-strategy). A leverage fill also reads the swap's feed price. Its up and down caps, its leverage band and its lever-up floor all depend on it.

A `poke` call reverts in these cases:

* The pool is paused (`Paused`).
* The pool has no price band, so it reads no feed price (`NoBand`).
* The feed can't give a checked price: the sequencer is down or inside its grace period, or a price is stale or invalid. These errors come from the price feed. See [Price feeds and oracles](/how-pools-work/price-feeds-and-oracles.md).
* A loan asset the pool holds, has supplied or owes has no checked price (`PriceUnchecked`).
* The recentring hook's update moves its price too far (`PokeMove`). See [Hooks](/how-pools-work/hooks.md).

Each successful call emits the pool's `Observed` with the price and its timestamp. A `recenter` is a separate call, made by the keeper, the pool operator or the controller hook. It emits the pool's `Recentered` instead.

The Everlong hook's `lastObservationTs()` returns its last accepted reading's feed stamp. It returns the block time instead when that stamp was no newer than the previous one.
