> ## 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 指令

> AMM Routing 指令的权威参考，包含在主网启用的六个变体 — 覆盖精确输入/精确输出交换和 wSOL 工具。

<Info>
  **本页内容由 AI 自动翻译，所有内容以英文版本为准。**

  [查看英文版 →](/products/routing/instructions)
</Info>

## 指令总览

| Tag | Discriminator                | 精确 | 变体 |
| --- | ---------------------------- | -- | -- |
| 0   | `SwapBaseInWithUserAccount`  | 输入 | 旧版 |
| 1   | `SwapBaseOutWithUserAccount` | 输出 | 旧版 |
| 5   | `CreateSyncNative`           | —  | 工具 |
| 6   | `CloseTokenAccount`          | —  | 工具 |
| 8   | `SwapBaseIn`                 | 输入 | 当前 |
| 9   | `SwapBaseOut`                | 输出 | 当前 |

**说明：**

* **精确：** 调用者固定的金额类型（输入 = 精确输入 `amount_in`；输出 = 精确输出 `amount_out`）。
* **变体：** 旧版指令要求 `limit_prices` 非空，即使路由中没有 CLMM hop。当前指令（8 / 9）允许 `limit_prices` 为空，表示「不进行检查」，推荐在新代码中使用。

所有交换变体都通过**用户控制的 ATA** 路由中间代币 — 用户拥有输入 ATA、所有中间 ATA 和输出 ATA。对于新的集成，使用 **tag 8（`SwapBaseIn`）** 或 **tag 9（`SwapBaseOut`）**，除非你有特别的理由调用旧版变体。

## 当前交换指令（推荐）

这些是新代码应该使用的入口点。参数结构与旧版变体相同，但 `limit_prices` 可以为空。

### `SwapBaseIn` (tag 8)

精确输入多跳交换。调用者固定 `amount_in`；路由器逐跳执行，并断言最终金额不低于 `minimum_amount_out`。

**参数**

```
amount_in:            u64
minimum_amount_out:   u64
limit_prices:         VecDeque<u128>  // 可选；空 deque 表示不进行每跳 CLMM 价格检查
```

**账户**

```
[
  <user_input_ata> W S,         // 签名者；余额 >= amount_in
  <user_intermediate_ata_1> W,  // 每个中间跳一个
  ... <user_intermediate_ata_N> W,
  <user_output_ata> W,
  <token_program>,

  <pool_program_hop_1>,         // 确定第 1 跳属于哪个 AMM 系列
  <pool_state_hop_1> W,
  ... <hop 1 所需的其他账户>,

  <pool_program_hop_2>,
  <pool_state_hop_2> W,
  ... <hop 2 账户>,

  ... [按跳重复]
]
```

每跳的确切账户列表取决于底层 AMM 程序（AMM v4 / CPMM / CLMM / Stable）。路由器依次 CPI 进入每个程序，并验证程序 ID 与四个受支持程序之一匹配。

**前置条件**

* 调用者使用 `user_input_ata` 签名。
* `user_input_ata.amount >= amount_in`。
* 每个中间用户 ATA 存在且由调用者拥有。
* 如果任何跳是 CLMM 且你要强制执行价格边界，请为每个 CLMM 跳提供一个 `limit_prices` 条目。

**后置条件**

* `user_input_ata` 余额减少 `amount_in`。
* `user_output_ata` 余额增加 ≥ `minimum_amount_out`。
* 每个中间 ATA 的净变化为零（路由消费前一跳产生的数量）。

**常见错误**

* `ExceededSlippage` — 最终输出 \< `minimum_amount_out`。
* `InvalidInput` — 路由为空、账户格式不正确或不支持的 `pool_program`。
* `SqrtPriceX64` — CLMM 跳的价格超出提供的 `limit_prices` 边界（仅当 `limit_prices` 非空时）。

***

### `SwapBaseOut` (tag 9)

精确输出多跳交换。调用者固定 `amount_out`；路由器断言实际输入不超过 `maximum_amount_in`。

**参数**

```
maximum_amount_in:   u64
amount_out:          u64
limit_prices:        VecDeque<u128>  // 可选；空 deque 表示不进行每跳 CLMM 价格检查
```

**账户** — 结构与 tag 8 相同。

**前置条件**

* 调用者使用 `user_input_ata` 签名；余额 `>= maximum_amount_in`（最坏情况）。
* 每个中间 ATA 和输出 ATA 存在。

**后置条件**

* `user_input_ata` 减少所需的实际金额（≤ `maximum_amount_in`）。
* `user_output_ata` 增加恰好 `amount_out`。

**常见错误**

* `ExceededSlippage` — 所需输入超过 `maximum_amount_in`。
* `InvalidInput`、`SqrtPriceX64` — 与 tag 8 相同。

***

## 旧版交换指令

这些较旧的变体在实时程序上仍可调用，在此出于完整性而记录。对于新代码，优先使用 tag 8 / tag 9；下面两个旧版变体都要求 `limit_prices` 非空，即使没有 CLMM 跳，这使得它们的使用变得笨拙。

### `SwapBaseInWithUserAccount` (tag 0)

精确输入多跳交换，在形状上与 tag 8 相同，但有更严格的 `limit_prices` 要求。

**参数**

```
amount_in:           u64
minimum_amount_out:  u64
limit_prices:        VecDeque<u128>  // 必需，非空
```

**账户** — 与 `SwapBaseIn`（tag 8）形状相同。所有中间槽必须是调用者拥有的 ATA。

**前置条件**

* 调用者使用 `user_input_ata` 签名。
* `user_input_ata.amount >= amount_in`。
* 所有中间用户 ATA 存在且由调用者拥有。
* `limit_prices` 非空（每个 CLMM 跳一个条目；若没有 CLMM 跳，用占位符填充）。

**后置条件**

* `user_input_ata` 余额减少 `amount_in`。
* `user_output_ata` 余额增加 ≥ `minimum_amount_out`。

**常见错误**

* `ExceededSlippage`。
* `InvalidInput` — 在此旧版变体上拒绝空的 `limit_prices`。
* `SqrtPriceX64`。

***

### `SwapBaseOutWithUserAccount` (tag 1)

精确输出交换，`SwapBaseOut`（tag 9）的旧版对应项。

**参数**

```
maximum_amount_in:   u64
amount_out:          u64
limit_prices:        VecDeque<u128>  // 必需，非空
```

**账户** — 与 tag 0 / tag 9 形状相同。

**前置条件**

* 调用者使用 `user_input_ata` 签名。
* `user_input_ata.amount >= maximum_amount_in`。
* 所有中间用户 ATA 存在且由调用者拥有。
* `limit_prices` 非空。

**后置条件**

* `user_input_ata` 减少所需的实际金额（≤ `maximum_amount_in`）。
* `user_output_ata` 增加恰好 `amount_out`。

**常见错误**

* `ExceededSlippage`。
* `InvalidInput`。
* `SqrtPriceX64`。

***

## 工具指令

### `CreateSyncNative` (tag 5)

在一步内创建（如果缺失）并同步 wSOL ATA。在与交换一起内联包装 SOL 时很方便。

**参数**

```
amount: u64    // 要包装的 SOL（lamports）
```

**账户**

```
[
  <user_wsol_ata> W,            // wSOL 的 ATA；如果缺失则创建
  <user_native_account> W S,    // 签名者；从此处扣除 SOL
  <wsol_mint>,
  <system_program>,
  <token_program>,
  <associated_token_program>,
]
```

**效果**

* 如果 `user_wsol_ata` 不存在，则创建它。
* 从签名者的原生 SOL 余额转入 `amount` lamports 到 ATA。
* 在 ATA 上调用 `SyncNative`，使其代币余额反映新增 lamports。

**常见错误**

* `InvalidOwner` — `user_wsol_ata` 的所有者不是签名者。

***

### `CloseTokenAccount` (tag 6)

关闭一个代币账户并将其租金返回到目的钱包。与 `CreateSyncNative` 配对：在 wSOL 腿交换后，调用 `CloseTokenAccount` 以恢复支持 wSOL ATA 的租金。

**参数** — 无。

**账户**

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

**效果**

* 关闭 `token_account_to_close`。
* 将租金免除 lamport 余额（主网上标准 SPL Token 账户约 0.00203928 SOL）转入 `destination_for_rent`。
* 代币账户必须有零代币余额。

**常见错误**

* `InvalidOwner` — 调用者不是 ATA 所有者。
* 代币账户余额非零。

***

## 后续步骤

* [`products/routing/code-demos`](/zh/products/routing/code-demos) — 用 TypeScript 构建这些指令。
* [`products/routing/accounts`](/zh/products/routing/accounts) — 每个 AMM 的分发密钥和每跳账户布局。
* [`reference/error-codes`](/zh/reference/error-codes) — 完整的 `RouteError` 列表。
