> 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/use-efficient/trade.md).

# Trade

How traders and arbitrageurs swap against an Efficient pool: the pair, the swap call, limits and halts, the preview, reads, common reverts and a typical arbitrage.

Any address can swap against an Efficient pool through its `swap` call, with no allowlist. The call and the checks on this page belong to the pool itself, so they hold no matter which hooks price the pool. A few apply only to a pool with a price band or a lending market, and the page flags each one.

Traders can also reach a pool through `PoolSwapAdapter` or through an aggregator or solver route. The adapter is a thin entry point that refunds unused input. [Swaps for aggregators and solvers](/integrate/swaps-for-aggregators-and-solvers.md) covers both routes and the `Swap` event. [Deployments](/reference/deployments.md) lists where pools run.

## Pairs

**Each pool trades its pool asset against its first loan asset only, in either direction.** The first loan asset is the pair's other token. It's a token the pool can borrow: USDC, in an Efficient pool that trades BTC against USDC. Any other token the pool can borrow is also a loan asset.

A sell pays in the pool asset and receives the first loan asset. A buy is the reverse. Any other pair reverts with `InvalidPair`.

`asset()` and `loanAsset()` return the pair. `loanCount()` and `loanConfig(idx)` describe every loan asset the pool has registered.

Trades between two loan assets go only through `swapLoan`. It needs the optional loan-to-loan swap hook and feature bit 6 (value 64). The swap path is part of the pool and is in audit. Each pool adds its loan-to-loan swap hook at deployment, or later through a new hook set.

Efficient doesn't ship a loan-to-loan swap hook yet. On a pool without one, `swapLoan` reverts with `LoanSwapDisabled`, as [Hooks](/how-pools-work/hooks.md) explains. On a pool with the hook but bit 6 clear, it reverts with `FeatureDisabled(6)`.

## The swap call

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

| Parameter      | Meaning                                                                              |
| -------------- | ------------------------------------------------------------------------------------ |
| `tokenIn`      | The token the trader pays: the pool asset for a sell, the first loan asset for a buy |
| `tokenOut`     | The token the trader receives                                                        |
| `amountIn`     | The most input the pool may take, in `tokenIn`'s base units. Must be above zero.     |
| `minAmountOut` | The least output the trader accepts after the fee, in `tokenOut`'s base units        |
| `to`           | The address that receives the output. Can't be the zero address.                     |
| `deadline`     | A Unix timestamp. The swap reverts in any block with a later timestamp.              |

The pool pulls the input from the caller with `transferFrom` before it pays out, and makes no callback. So the caller needs to hold the input and approve the pool first. An approval of `amountIn` covers any fill.

The call returns two values. `amountInUsed` is the input the pool took, which can be less than `amountIn`. `amountOut` is the output `to` received after the fee.

Every swap is exact input, because the invariant hook prices only a given input. To aim at a set output, a trader searches for the input with `previewSwap`.

## How a fill is priced

**The pool's hooks price each fill and its fee together, once per swap.** The pool checks both before it settles.

* **The fee** comes out of the output: in the loan asset on a sell, and in the pool asset on a buy. It stays inside the floor and cap that [Fees](/use-efficient/fees.md) covers.
* **The price band**, in a pool that has one, holds every fill, fee included, near the feed price. If a fill lands outside it, the swap reverts with `PriceBand`. A pool with no price band reads no feed price on a swap, so its fills get no band check. [Hooks](/how-pools-work/hooks.md) has the detail.

### Leverage fills on Everlong vaults

**An Everlong vault with leverage switched on can fill a swap on the Everlong hook's leverage curve.** The pool checks that fill like any other. The hook quotes each swap on its curve at its dynamic fee, and on its leverage curve at its spread. It then fills on whichever pays the trader strictly more. A leverage fill that breaks a hook rule gives way to the curve's fill, so output isn't always monotone in size. [The Everlong strategy](https://docs.foreverlong.io/everlong/everlong-strategy) sets out those rules.

## Limits on a swap

**A sell fills up to its ceiling.** The trader keeps any input the fill doesn't use. The ceiling depends on whether the pool can borrow the first loan asset.

If it can, the ceiling is the smaller of the pool's credit room and the per-swap cap. The credit room is what the pool can still pay out under its LTV pin. [Credit and collateral](/how-pools-work/credit-and-collateral.md) works it out.

If it can't, the ceiling is the smaller of the per-swap cap and the pool's cash in that asset, held or supplied. While debt remains from before that asset's borrowing went off, the credit room bounds that ceiling too.

The per-swap cap is `maxSwapNotional` in `loanConfig(0)`, where zero means no cap. A sell with no room left, in credit room or cash, reverts with `RoomExhausted`.

**Funding never cuts a sell short.** The pool pays first from the loan asset it holds. A pool with lending markets then withdraws supply and, where it can borrow, borrows the rest. See [Just-in-time financing](/how-pools-work/just-in-time-financing.md). A sell the lending markets can't fund reverts whole, usually with `InsufficientLiquidity`.

A buy's ceiling is the pool asset the pool holds. In a pool that borrows, it also includes the collateral the pool has posted. A buy whose input exceeds the per-swap cap fills at the cap, and the trader keeps the rest of the input.

The hooks can stop a fill before the ceiling. The Everlong hook does this at the edge of its curve's span. `minAmountOut` applies to a partial fill too, so a partial fill below it reverts with `Slippage`. [The pool and its book](/how-pools-work/the-pool-and-its-book.md) follows a sell and a buy step by step.

## When swaps halt

**Each condition below stops swaps until it clears.** [Common reverts](#common-reverts) lists the error for each.

* A pause stops sells, lever-up fills included, and loan-to-loan swaps. Buys go on.
* A direction switched off stops only that direction.
* If the pool can borrow the first loan asset, a broken peg on it stops sells only.
* In a pool with a price band, a stale or invalid [feed](/how-pools-work/price-feeds-and-oracles.md) for the pool asset or the first loan asset stops every swap. A sequencer outage stops every swap in such a pool too.
* So does an unchecked price on a loan asset the pool holds, has supplied or owes.
* A financing router pause by the protocol Safe stops sells that need to borrow. Sells paid from loan asset held or supplied still fill.

The pool operator or the guardian can pause a pool, switch a direction off, narrow the price band or lower the per-swap cap. Only the pool operator can undo these. See [Roles and governance](/run-a-pool/roles-and-governance.md).

## The preview

```solidity
function previewSwap(bool poolAssetIn, uint256 amountIn)
    external
    view
    returns (uint256 amountInUsed, uint256 amountOut, uint256 feeWad);
```

The preview returns the input the pool would use, the output after the fee and the fee rate. `poolAssetIn` is `true` for a sell and `false` for a buy. `feeWad` is the fee as a fraction of the gross output, with 18 decimals, so a 10% fee reads 1e17.

**The preview quotes the fill a swap would get on the same state.** That includes a leverage fill. It runs the swap's planning checks, but not the deadline, recipient or minimum output. It differs from the swap in three ways:

1. **It caps a sell at what the pool can fund** from the loan asset it holds and its lending markets. The swap can pick a lever-up fill the pool can't fund, and revert.
2. **It stops before settlement,** so a swap can still revert where the financing router moves funds or the credit check runs again.
3. **It projects the interest a swap accrues** first. So in a pool that borrows, a preview-sized sell can still hit the rate ceiling on a lending market not yet accrued.

A preview reserves nothing. Other fills, recentres, price observations, fee settings and other borrowers can change the result before the swap runs.

## Reads before a swap

Calls marked Lens are on the read-only lens. It answers with an `ok` flag instead of reverting. [Swaps for aggregators and solvers](/integrate/swaps-for-aggregators-and-solvers.md) describes the rest of the lens.

| Call                                            | What it shows                                                                                                                                                                                                                                                      |
| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `paused()`                                      | Whether the pool is paused                                                                                                                                                                                                                                         |
| `switches()`                                    | The feature bitmap, its first return value. Bit 1 (value 2) enables sells, bit 2 (value 4) buys and bit 6 (value 64) loan-to-loan swaps. Bit 5 (value 32) allows lever-up fills.                                                                                   |
| `loanConfig(idx)`                               | For each loan asset: token, decimals, price band, fee floor, per-swap cap, reserve target and the balance the pool holds                                                                                                                                           |
| `limits()`                                      | The pool-wide fee floor and fee cap, among other limits                                                                                                                                                                                                            |
| Lens `price(pool)`                              | The pool asset's feed price in the first loan asset, when it was observed, and whether the first loan asset is on its peg                                                                                                                                          |
| `swapContext(poolAssetIn, amountIn)`            | The request the pool would hand its hooks now. It reverts where the pool refuses before pricing: a sell while paused or without room, a sell off peg if the pool can borrow the first loan asset, a direction switched off, a zero input or a price it can't read. |
| `previewSwap(poolAssetIn, amountIn)`            | The quote a swap would get now, as [the preview](#the-preview) describes                                                                                                                                                                                           |
| Lens `previewSwap(pool, poolAssetIn, amountIn)` | The same quote with an `ok` flag in place of a revert, for scanning sizes                                                                                                                                                                                          |
| Lens `levQuote(pool, poolAssetIn, amountIn)`    | On an Everlong vault, the leverage fill alone and whether the swap would fill on it                                                                                                                                                                                |

## Common reverts

| Error                                                               | Raised by         | Cause                                                                                                                                         |
| ------------------------------------------------------------------- | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `Expired`                                                           | Pool              | The block's timestamp is later than `deadline`                                                                                                |
| `InvalidAmount`                                                     | Pool              | `amountIn` is zero or `to` is the zero address                                                                                                |
| `InvalidPair`                                                       | Pool              | The tokens aren't the pool asset and the first loan asset                                                                                     |
| `Paused`                                                            | Pool              | A sell while the pool is paused                                                                                                               |
| `FeatureDisabled(uint8)`                                            | Pool              | Sells (bit 1) or buys (bit 2) are switched off, or a loan-to-loan swap finds bit 6 clear                                                      |
| `SequencerDown`, `SequencerGrace`                                   | Price feed        | The chain's sequencer is down or inside its grace period                                                                                      |
| `StalePrice(address)`, `InvalidPrice(address)`                      | Price feed        | A USD feed's latest round is older than the token's `heartbeat`, or its answer is invalid                                                     |
| `PegBroken`                                                         | Pool              | A sell while the first loan asset fails its peg check, if the pool can borrow it                                                              |
| `PriceUnchecked`                                                    | Pool              | No checked price for the first loan asset, or for a loan asset the pool holds, has supplied or owes                                           |
| `RoomExhausted`                                                     | Pool              | A sell finds no room left: no credit room under the LTV pin or, if the pool can't borrow the first loan asset, no cash of it held or supplied |
| `FeeOutOfBounds`                                                    | Pool              | The fee hook's fee is below the higher of the fee floors in `limits()` and `loanConfig(0)`, or above the fee cap                              |
| `FillInvalid`                                                       | Pool              | The fill is empty, for example from too small an input                                                                                        |
| `Slippage`                                                          | Pool              | The output after the fee is below `minAmountOut`                                                                                              |
| `OutputAboveCeiling`                                                | Pool              | The fill pays more than the swap's ceiling or, in `previewSwap` only, the funding passes didn't settle                                        |
| `LoanSwapDisabled`                                                  | Pool              | `swapLoan` on a pool with no loan-to-loan swap hook                                                                                           |
| `NotionalCap`                                                       | Pool              | A loan-to-loan swap's `amountIn` exceeds its input asset's per-swap cap                                                                       |
| `PriceBand`                                                         | Pool              | In a pool with a price band, the fill's price is outside the band around the feed price                                                       |
| `LedgerBoundBreached`                                               | Pool              | The pool's credit check failed at settlement                                                                                                  |
| `CustodyMismatch`                                                   | Pool              | The pool received less input than it pulled, for example from a fee-on-transfer token                                                         |
| `InsufficientLiquidity(uint256)`, `InsufficientCollateral(uint256)` | Financing router  | The lending markets can't fund a sell or, in a pool that borrows, the pool can't release enough collateral to pay a buy                       |
| `RateCeiling`, `DebtCapExceeded`, `VenueOverPinned`, `Unhealthy`    | Financing router  | The fund re-check refuses a borrow for a sell. See [Credit and collateral](/how-pools-work/credit-and-collateral.md#the-fund-re-check).       |
| The input token's own error                                         | Input token       | The caller hasn't approved enough of the input token or doesn't hold enough                                                                   |
| `BadPair`, `BadRecipient`, `ZeroAmount`, `Misreport`                | `PoolSwapAdapter` | The adapter's own checks, listed in [Swaps for aggregators and solvers](/integrate/swaps-for-aggregators-and-solvers.md)                      |

Some errors come from outside the pool: from the price feed, the financing router or the hooks. They reach the caller as that contract's own revert data.

## A typical arbitrage

**An arbitrage opens when a pool's quote falls behind other markets.** It pays once the gap exceeds the pool's fee plus the arbitrageur's costs. On an Everlong vault, the curve's quote lags after a move, as [The Everlong strategy](https://docs.foreverlong.io/everlong/everlong-strategy) explains.

If an Everlong vault quotes cbBTC below other markets, an arbitrageur buys from the vault and sells elsewhere. Each unit bought on the curve raises the vault's price. Buying stops paying once that price, with the fee and costs, reaches the other market's.

In a pool with a price band, an arbitrage fill, fee included, can't sit further from the feed price than the band allows either way. The feed price comes from two USD prices, so it can itself differ from the price on other markets.

On the pool's side, an arbitrage takes six steps:

1. Read the pair with `asset()` and `loanAsset()`, and pick the direction. After a rise elsewhere, buy from the pool (`poolAssetIn` false). After a fall, sell to it (`poolAssetIn` true).
2. Check that the direction is open with the reads in [Reads before a swap](#reads-before-a-swap).
3. Quote each size with the pool's preview, or the Lens `previewSwap` from the same table, and take its average price. For a sell, that's output over input used. For a buy, it's input used over output. Stop where the last unit, after the fee, no longer beats the other market. Trade only if the gain covers gas and the other leg. If `amountInUsed` comes back below `amountIn`, size down to it.
4. Set a near `deadline`. Set `minAmountOut` from the quote less a margin, because it's the only guard against the fee or the curve moving before the swap lands.
5. Approve the pool for `amountIn` and call `swap`, or approve `PoolSwapAdapter` and call its `swapExactIn`. If the arbitrageur's contract trades the other leg in the same transaction, a revert on either leg undoes both.
6. Size the other leg from the `amountInUsed` and `amountOut` the call reports, not from the quote.

Everlong runs its own arbitrage bot against Everlong vaults. It pays the same fee through the same `swap` as any other trader.
