> **Can't find what you're looking for?** Use `search_docs` on the docs MCP server at `https://viem.sh/api/mcp` to find what you need.

# Swap with a PropAMM Pool

## Overview

A PropAMM pool exchanges a fixed pair at an oracle-bound price for approved takers and recipients.
Supply the pool address explicitly. The swap pulls input tokens from the transaction sender, so the
sender must hold them. The swap action approves the pool in the same transaction.

## Recipes

These recipes assume you have [set up a Tempo client](/tempo) and have an approved caller
and recipient.

### Quote a Swap

Use [`getSwapQuote`](/tempo/actions/propAmm.getSwapQuote) to preview the output for an exact amount
of the pool's base token. Use `baseToQuote: false` to send quote and receive base. The quote also
returns a swap `request` containing the route, quoted limit, and oracle observation.

:::code-group
```ts twoslash [example.ts]
import { parseUnits } from 'viem'
import { client } from './viem.config'

const { amountOut, price, updatedAt } = await client.propAmm.getSwapQuote({
  amountIn: parseUnits('1', 6), // Use the base token's decimals.
  mode: 'exactInput',
  pool: '0x...',
})
console.log(amountOut, price, updatedAt)
```

```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::

### Swap an Exact Input

Get a fresh quote, then pass its `request` to
[`swapSync`](/tempo/actions/propAmm.swap). The action approves the pool and swaps in one Tempo
transaction. The sender must hold the input tokens.

By default, swaps send base and receive quote, deliver output to the sending account, and expire
five minutes after the call. Set `baseToQuote`, `recipient`, or `deadline` to override these defaults.

:::code-group
```ts twoslash [example.ts]
import { parseUnits } from 'viem'
import { client } from './viem.config'

const { request } = await client.propAmm.getSwapQuote({
  amountIn: parseUnits('1', 6),
  mode: 'exactInput',
  pool: '0x...',
})

const trade = await client.propAmm.swapSync(request) // [!code focus]
console.log(trade.amountOut, trade.receipt.transactionHash)
```

```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::

### Swap for an Exact Output

For an exact output, call [`getSwapQuote`](/tempo/actions/propAmm.getSwapQuote) with
`mode: 'exactOutput'`, then call [`swap`](/tempo/actions/propAmm.swap) or
[`swapSync`](/tempo/actions/propAmm.swap) with the returned `request`. The action approves
`maxAmountIn` and submits the swap in one transaction. The `.call` builder defines only the swap
call, so add an approval when assembling a batch manually.

:::code-group
```ts twoslash [example.ts]
import { parseUnits } from 'viem'
import { client } from './viem.config'

const { request } = await client.propAmm.getSwapQuote({
  amountOut: parseUnits('1', 6),
  mode: 'exactOutput',
  pool: '0x...',
})

const trade = await client.propAmm.swapSync(request) // [!code focus]
console.log(trade.amountIn, trade.receipt.transactionHash)
```

```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::

If an exact-output swap spends less than `maxAmountIn`, the unused allowance remains on the input token.

The customer ID defaults to the taker address left-padded to 32 bytes. Provide the same explicit
`customerId` to the quote and swap when separating customer routes that share a wallet.

## Best Practices

### Check Access and Inventory

Check `takerAllowed` for the transaction sender. Resolve the destination with `resolveRecipient`
before checking `recipientAllowed`. The pool must hold enough output tokens, and the sender must
hold enough input tokens. Quotes do not reserve inventory, so simulate close to submission.

### Bind the Oracle and Price Limit

The returned `request` binds the swap to the quoted amount and oracle observation. Choose `oraclePriceToleranceBps`,
`minAmountOut`, or `maxAmountIn` according to the execution policy. A stale oracle, changed price,
expired deadline, paused pool, or changed permissions can revert the swap after the quote.

## See More

<Cards>
  <Card icon="lucide:square-function" title="Swap Action" description="Parameters and return values for PropAMM swaps." to="/tempo/actions/propAmm.swap" />

  <Card icon="lucide:arrow-left-right" title="Stablecoin Exchange" description="Trade stablecoins through Tempo's enshrined exchange." to="/tempo/guides/stablecoin-exchange" />
</Cards>
