> ## Documentation Index
> Fetch the complete documentation index at: https://docs.raydium.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Routing instructions

> Reference for the AMM Routing instructions enabled on mainnet — six variants covering exact-input / exact-output swaps and the wSOL utilities.

<Info>
  This page is the authoritative instruction reference for the AMM Routing program. For code examples, see [`products/routing/code-demos`](/products/routing/code-demos). For error meanings, see [`reference/error-codes`](/reference/error-codes).
</Info>

## Instruction summary

| Tag | Discriminator                | Exact  | Variant |
| --- | ---------------------------- | ------ | ------- |
| 0   | `SwapBaseInWithUserAccount`  | Input  | Legacy  |
| 1   | `SwapBaseOutWithUserAccount` | Output | Legacy  |
| 5   | `CreateSyncNative`           | —      | Utility |
| 6   | `CloseTokenAccount`          | —      | Utility |
| 8   | `SwapBaseIn`                 | Input  | Current |
| 9   | `SwapBaseOut`                | Output | Current |

**Legend:**

* **Exact:** which amount is fixed by the caller (Input = exact-input `amount_in`; Output = exact-output `amount_out`).
* **Variant:** Legacy instructions require a non-empty `limit_prices` deque even if no CLMM hop is in the route. Current instructions (8 / 9) treat an empty `limit_prices` as "no checks", which is the recommended path for new code.

All swap variants route intermediate tokens through **user-controlled ATAs** — the user owns the input ATA, every intermediate ATA, and the output ATA. For new integrations, use **tag 8 (`SwapBaseIn`)** or **tag 9 (`SwapBaseOut`)** unless you have a specific reason to call a Legacy variant.

## Current swap instructions (recommended)

These are the entry points new code should use. Argument structure is the same as the Legacy variants but `limit_prices` may be empty.

### `SwapBaseIn` (tag 8)

Exact-input multi-hop swap. The caller fixes `amount_in`; the router executes hop-by-hop and asserts that the final amount lands at or above `minimum_amount_out`.

**Arguments**

```
amount_in:            u64
minimum_amount_out:   u64
limit_prices:         VecDeque<u128>  // optional; empty deque means no per-hop CLMM price check
```

**Accounts**

```
[
  <user_input_ata> W S,         // signer; balance >= amount_in
  <user_intermediate_ata_1> W,  // one per intermediate hop
  ... <user_intermediate_ata_N> W,
  <user_output_ata> W,
  <token_program>,

  <pool_program_hop_1>,         // identifies which AMM family hop 1 is
  <pool_state_hop_1> W,
  ... <other accounts required by hop 1's program>,

  <pool_program_hop_2>,
  <pool_state_hop_2> W,
  ... <hop 2 accounts>,

  ... [repeat per hop]
]
```

The exact account list per hop depends on the underlying AMM program (AMM v4 / CPMM / CLMM / Stable). The router CPIs into each in turn and validates the program ID matches one of the four supported programs.

**Pre-conditions**

* Caller signs with `user_input_ata`.
* `user_input_ata.amount >= amount_in`.
* Each intermediate user ATA exists and is owned by the caller.
* If any hop is CLMM and you want price-bound enforcement, supply one `limit_prices` entry per CLMM hop.

**Post-conditions**

* `user_input_ata` balance decreased by `amount_in`.
* `user_output_ata` balance increased by ≥ `minimum_amount_out`.
* Each intermediate ATA is left with zero net change (the route consumes whatever it produced one hop earlier).

**Common errors**

* `ExceededSlippage` — final output \< `minimum_amount_out`.
* `InvalidInput` — empty route, malformed accounts, or unsupported `pool_program`.
* `SqrtPriceX64` — a CLMM hop's price moved outside the supplied `limit_prices` bound (only when `limit_prices` is non-empty).

***

### `SwapBaseOut` (tag 9)

Exact-output multi-hop swap. The caller fixes `amount_out`; the router asserts that the actual input does not exceed `maximum_amount_in`.

**Arguments**

```
maximum_amount_in:   u64
amount_out:          u64
limit_prices:        VecDeque<u128>  // optional; empty deque means no per-hop CLMM price check
```

**Accounts** — same structure as tag 8.

**Pre-conditions**

* Caller signs with `user_input_ata`; balance `>= maximum_amount_in` (worst case).
* Each intermediate and the output ATA exist.

**Post-conditions**

* `user_input_ata` decreased by the actual amount needed (≤ `maximum_amount_in`).
* `user_output_ata` increased by exactly `amount_out`.

**Common errors**

* `ExceededSlippage` — required input exceeds `maximum_amount_in`.
* `InvalidInput`, `SqrtPriceX64` — as for tag 8.

***

## Legacy swap instructions

These older variants are still callable on the live program and are documented here for completeness. Prefer tag 8 / tag 9 for new code; both Legacy variants below require a non-empty `limit_prices` deque even when no CLMM hop is involved, which makes them awkward to use.

### `SwapBaseInWithUserAccount` (tag 0)

Exact-input multi-hop swap, identical in shape to tag 8 but with the stricter `limit_prices` requirement.

**Arguments**

```
amount_in:           u64
minimum_amount_out:  u64
limit_prices:        VecDeque<u128>  // required, non-empty
```

**Accounts** — same shape as `SwapBaseIn` (tag 8). All intermediate slots must be ATAs owned by the caller.

**Pre-conditions**

* Caller signs with `user_input_ata`.
* `user_input_ata.amount >= amount_in`.
* All intermediate user ATAs exist and are owned by the caller.
* `limit_prices` is non-empty (one entry per CLMM hop; pad with placeholder values if no CLMM hop is involved).

**Post-conditions**

* `user_input_ata` balance decreased by `amount_in`.
* `user_output_ata` balance increased by ≥ `minimum_amount_out`.

**Common errors**

* `ExceededSlippage`.
* `InvalidInput` — empty `limit_prices` is rejected on this Legacy variant.
* `SqrtPriceX64`.

***

### `SwapBaseOutWithUserAccount` (tag 1)

Exact-output swap, the Legacy counterpart to `SwapBaseOut` (tag 9).

**Arguments**

```
maximum_amount_in:   u64
amount_out:          u64
limit_prices:        VecDeque<u128>  // required, non-empty
```

**Accounts** — same shape as tag 0 / tag 9.

**Pre-conditions**

* Caller signs with `user_input_ata`.
* `user_input_ata.amount >= maximum_amount_in`.
* All intermediate user ATAs exist and are owned by the caller.
* `limit_prices` is non-empty.

**Post-conditions**

* `user_input_ata` decreased by the actual amount needed (≤ `maximum_amount_in`).
* `user_output_ata` increased by exactly `amount_out`.

**Common errors**

* `ExceededSlippage`.
* `InvalidInput`.
* `SqrtPriceX64`.

***

## Utility instructions

### `CreateSyncNative` (tag 5)

Create (if missing) and sync a wSOL ATA in one step. Convenient when wrapping SOL inline alongside a swap.

**Arguments**

```
amount: u64    // SOL to wrap (lamports)
```

**Accounts**

```
[
  <user_wsol_ata> W,            // ATA for wSOL; created if missing
  <user_native_account> W S,    // signer; SOL is debited from here
  <wsol_mint>,
  <system_program>,
  <token_program>,
  <associated_token_program>,
]
```

**Effect**

* Creates `user_wsol_ata` if it does not yet exist.
* Transfers `amount` lamports from the signer's native SOL balance to the ATA.
* Calls `SyncNative` on the ATA so its token balance reflects the new lamports.

**Common errors**

* `InvalidOwner` — `user_wsol_ata`'s owner is not the signer.

***

### `CloseTokenAccount` (tag 6)

Close a token account and return its rent to the destination wallet. Pairs with `CreateSyncNative`: after a wSOL-leg swap, call `CloseTokenAccount` to recover the rent that backed the wSOL ATA.

**Arguments** — none.

**Accounts**

```
[
  <token_account_to_close> W,
  <destination_for_rent> W,
  <owner> S,
  <token_program>,
]
```

**Effect**

* Closes `token_account_to_close`.
* Transfers the rent-exempt lamport balance (\~0.00203928 SOL on mainnet for a vanilla SPL Token account) to `destination_for_rent`.
* The token account must have zero token balance.

**Common errors**

* `InvalidOwner` — caller is not the ATA owner.
* Token account balance is non-zero.

***

## Where to go next

* [`products/routing/code-demos`](/products/routing/code-demos) — building each of these instructions in TypeScript.
* [`products/routing/accounts`](/products/routing/accounts) — per-AMM dispatch keys and per-hop account layout.
* [`reference/error-codes`](/reference/error-codes) — full `RouteError` list.
