> For the complete documentation index, see [llms.txt](https://docs.metric.xyz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.metric.xyz/reference/smart-contracts/swapping-directly-via-pool.md).

# Swapping directly via pool

Call swap on the pool and settle via the IMetricOmmSwapCallback callback.

Call `swap` directly on `MetricOmmPool` from a contract that implements `IMetricOmmSwapCallback`. Use this for full control over funding (vault, flash logic, aggregator settlement); otherwise prefer the Router, which handles settlement for you.

The sign of `amountSpecified` selects exact-input or exact-output. The Router uses separate `exactInput*` / `exactOutput*` calls.

### Swap Parameters

```solidity
function swap(
    address recipient,        // receives the output tokens
    bool zeroForOne,          // true = token0→token1, false = token1→token0
    int128 amountSpecified,   // positive = exact input, negative = exact output (non-zero)
    uint128 priceLimitX64,    // marginal price bound, Q64.64
    bytes calldata callbackData,   // forwarded to YOUR swap callback
    bytes calldata extensionData   // forwarded to the pool's swap extensions
) external returns (int128 amount0Delta, int128 amount1Delta);
```

* `amountSpecified == 0` reverts `InvalidAmount`.
* `priceLimitX64` is your slippage protection (Q64.64 marginal bound).
* `callbackData` is opaque: the pool never reads it; it's handed back to your `metricOmmSwapCallback` so you can route context (payer, leg, funding source). `"0x"` if unused.
* `extensionData` is separate: the pool forwards it to its `beforeSwap` / `afterSwap` extension hooks, **not** to your callback. `"0x"` if the pool has no extensions or they need no input.
* Reverts `PoolPaused` if the pool is paused.
* A Price Provider revert arrives wrapped as `PriceProviderFailed(bytes reason)`, e.g. `PriceProviderFailed(FeedStalled())`.

{% hint style="warning" %}
**A swap can fill only part of your amount.** If the pool reaches `priceLimitX64` or runs out of liquidity first, `swap` still succeeds. Check the returned deltas before treating the trade as complete.
{% endhint %}

### Swap Callback

The pool settles Uniswap v3-style. Per swap, in order:

1. The pool computes deltas and **sends the output token to `recipient`** (the negative-delta side).
2. It calls `metricOmmSwapCallback` on `msg.sender`.
3. Your callback **transfers the owed input token to the pool** (the positive-delta side).
4. The pool balance-checks repayment and reverts `IncorrectDelta` if you underpaid.

Deltas (pool perspective): **positive** → you must send that token to the pool; **negative** → the pool already sent it to `recipient`; both are nonzero on a successful swap.

```solidity
/// @notice Any contract that calls IMetricOmmPool#swap must implement this.
interface IMetricOmmSwapCallback {
    /// @param amount0Delta  positive => pool must receive token0 from the payer; negative => pool sent it out
    /// @param amount1Delta  positive => pool must receive token1 from the payer; negative => pool sent it out
    /// @param callbackData  opaque bytes forwarded from the swap call
    function metricOmmSwapCallback(
        int256 amount0Delta,
        int256 amount1Delta,
        bytes calldata callbackData
    ) external;
}
```

{% hint style="danger" %}
Your callback **must verify `msg.sender` is a legitimate Metric pool** before paying; otherwise any contract can call it and drain funds.
{% endhint %}

{% hint style="info" %}
The callback can source input from a wallet, vault or flash operation. The pool does not pull input tokens or require upfront transfers; your callback pays the pool.
{% endhint %}

### Check before you pay

You can't get a live quote from inside a transaction for a pool priced by Chainlink or Pyth. The quoter's live path reads the Price Provider outside a swap, and those oracles refuse that read onchain. To price a pool from a contract, call `swap` and decide in `metricOmmSwapCallback`: pay if the deltas are acceptable, or revert with your own error and catch it around the `swap` call. To use it as a quote, revert with the deltas and decode them in the `catch`. Set `priceLimitX64` to stop at your price.

{% hint style="warning" %}
Execution uses the onchain provider quote; see [Liquidity and bins](/how-pools-work/liquidity-and-bins.md#execution-price) for pool pricing. On Ethereum, where to send the swap matters; see [Freshness and ordering](/how-pools-work/freshness-and-ordering.md#for-integrators).
{% endhint %}
