> ## 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.

# Toán học AMM v4

> Bất biến tích hằng số với quy ước phí của AMM v4, chuyển đổi giá từ reserve sang orderbook, xây dựng lưới lệnh mục tiêu, và bước giải quyết PnL.

<Info>
  **Trang này được dịch tự động bằng AI. Phiên bản tiếng Anh là bản chính thức.**

  [Xem bản tiếng Anh →](/products/amm-v4/math)
</Info>

## Bất biến

Pool duy trì `coin_reserve × pc_reserve = k`, trong đó (sau khi loại bỏ OpenBook vào 2026-07):

```
coin_reserve = coin_vault_balance - accrued_pnl_coin
pc_reserve   = pc_vault_balance   - accrued_pnl_pc
```

Hai điểm cần lưu ý:

1. Reserve hiện tại **chỉ từ vault**. Thuật ngữ open-order lịch sử (token mà pool đã ký quỹ dưới dạng lệnh giới hạn OpenBook) đã bị loại bỏ — nó thực tế đã bằng không từ lâu trước khi loại bỏ. Bạn có thể tính `k` trực tiếp từ số dư vault trên chuỗi.
2. Tích lũy PnL (`need_take_pnl_*`) được trừ đi để đường cong được bảo toàn khi admin quét phí. Nguyên tắc tương tự như loại trừ `protocol_fees_*` của CPMM.

Chương trình tính toán điều này thông qua `calc_total_without_take_pnl_no_orderbook` (biến thể nhận biết orderbook cũ đã bị loại bỏ).

Mỗi hoạt động `Swap*` đảm bảo `k' ≥ k` sau khi thêm phần phí LP trở lại reserve.

## Quy ước phí

AMM v4 sử dụng **phí tỷ lệ** (cặp tử số/mẫu số) thay vì quy ước `1/1_000_000` của CPMM / CLMM. Struct `Fees` trên chuỗi (xem [`Fees::initialize`](https://github.com/raydium-io/raydium-amm/blob/master/program/src/state.rs) trong mã nguồn chương trình) mặc định là:

```
Fees {
  min_separate_numerator:    5,
  min_separate_denominator:  10_000,   //  5/10_000 = 0.05%

  trade_fee_numerator:      25,
  trade_fee_denominator:    10_000,    // 25/10_000 = 0.25% — dùng cho định giá lệnh giới hạn OpenBook

  pnl_numerator:            12,
  pnl_denominator:          100,       // 12/100   = 12%   — phần của giao thức từ phí swap

  swap_fee_numerator:       25,
  swap_fee_denominator:     10_000,    // 25/10_000 = 0.25% — phí tổng cộng trên swap đường AMM
}
```

Giải thích (mặc định mainnet được công bố):

* **Tổng phí swap:** `swap_fee = amount_in × 25 / 10_000 = 0.25%` của đầu vào tổng cộng.
* **Phần giao thức:** `pnl_numerator / pnl_denominator = 12 / 100 = 12%` **của phí swap**, tính ra `0.25% × 12% = 0.03%` của khối lượng. Phần này tích lũy vào các bộ đếm PnL và được quét bởi `WithdrawPnl`.
* **Phần LP:** `88%` còn lại của phí swap, tính ra `0.25% × 88% = 0.22%` của khối lượng. Ở lại trong pool và làm tăng `k`.
* **Không có phần quỹ.** AMM v4 không có phân chia phí quỹ như CPMM/CLMM.

Lưu ý rằng `pnl_numerator / pnl_denominator` là một phân số **của phí**, không phải của khối lượng giao dịch — một sự hiểu lầm phổ biến về các tên trường này.

`trade_fee_numerator / trade_fee_denominator` (cũng là `25 / 10_000`) từng được sử dụng bởi tích hợp OpenBook khi tính giá bao gồm phí cho lưới lệnh giới hạn của AMM. Với mã OpenBook bị loại bỏ, trường này là dư thừa; phí swap hoạt động là `swap_fee_*`.

Những sai lệch từ các mặc định này hiếm gặp nhưng tồn tại trên một số pool cũ; luôn đọc phí từ `AmmInfo.fees` trước khi báo giá.

## Toán học swap trực tiếp (đường AMM)

Trường hợp đơn giản nhất: người dùng swap với vault của pool mà không tương tác với OpenBook. Reserve nội bộ của pool (bao gồm phân bổ trên sách) là mẫu số.

**SwapBaseIn (đầu vào chính xác):**

```
amount_after_fee = amount_in − ceil(amount_in × swap_fee_numerator / swap_fee_denominator)
amount_out = amount_after_fee × out_reserve
           / (in_reserve + amount_after_fee)
require(amount_out >= minimum_amount_out)
```

Reserve được sử dụng ở đây là số dư vault (trừ PnL tích lũy). Lịch sử công thức cũng thêm các token mà AMM đã khóa vào lệnh OpenBook; **thuật ngữ đó đã bị loại bỏ** — reserve hiệu quả hiện bằng số dư vault thô trừ PnL đang chờ xử lý. Đường dẫn `MonitorStep` / settle ngầm định từng làm mới phía OpenBook đã bị loại bỏ.

**SwapBaseOut (đầu ra chính xác):**

```
amount_in_after_fee = ceil(in_reserve × amount_out / (out_reserve − amount_out))
amount_in_gross     = ceil(amount_in_after_fee × swap_fee_denominator
                            / (swap_fee_denominator − swap_fee_numerator))
require(amount_in_gross <= maximum_amount_in)
```

## Tương tác sổ lệnh (lịch sử)

<Note>
  **Đã loại bỏ.** Xây dựng lưới được mô tả trong phần này phản ánh cách AMM v4 *ban đầu* phản chiếu đường cong lên thị trường OpenBook. Tích hợp OpenBook — bao gồm crank `MonitorStep` và logic lưới `build_orders` — đã **bị loại bỏ khỏi chương trình** (nâng cấp 2026-07). Toán học dưới đây được bảo tồn thuần túy như bối cảnh lịch sử cho những gì các tài khoản `target_orders` / `amm_open_orders` trên chuỗi từng được định kích thước.
</Note>

Riêng biệt từ swap của người dùng, AMM v4 từng đặt một **lưới** lệnh giới hạn trên thị trường OpenBook. Lưới được tính từ các tham số `AmmInfo`:

* **`depth`** — số mức giá trên mỗi bên.
* **`amount_wave`** — đơn vị cơ sở kích thước trên mỗi mức.
* **`min_size`**, **`coin_lot_size`**, **`pc_lot_size`** — ràng buộc thị trường OpenBook.
* **`state_data.swap_acc_coin_fee`**, **`swap_acc_pc_fee`** — bộ đếm phí tích lũy kể từ `TakePnl` cuối cùng.

Chương trình lấy giá trên mỗi mức bằng cách đi ra từ giá đường cong hiện tại theo các bước tỷ lệ hằng số:

```
price_level(k) = curve_price × (1.0001 ^ k)       # về mặt khái niệm
size_level(k)  = amount_wave × f(depth, k)        # được giảm dần theo depth
```

Giá và kích thước chính xác được xác định bởi `target_orders` được tính trong `build_orders` và so sánh với `amm_open_orders` mỗi `MonitorStep`. Bất kỳ sự khác biệt nào dẫn đến hủy + đăng ký mới. Các lệnh mới được điền trên OpenBook giải quyết vào vault của pool trên hoạt động tiếp theo làm mới phía OpenBook.

Các nhà tích hợp hiếm khi cần tính lưới — người giữ Raydium duy trì nó — nhưng sẽ hữu ích khi biết rằng:

* Một pool có **thanh khoản trên sách** đáng kể có thanh khoản đó đóng góp vào `k`, không nằm không hoạt động.
* Một thị trường OpenBook cũ (hàng đợi sự kiện đầy, crank bị chặn) ngăn cập nhật lưới; AMM sau đó có thể báo giá các giá khác với sổ lệnh hiển thị cho đến crank tiếp theo.

## Bước giải quyết (PnL)

Phần giao thức 0.03% tích lũy vào `state_data.need_take_pnl_coin` và `state_data.need_take_pnl_pc`. `TakePnl` di chuyển các số tiền này ra khỏi vault đến đích được chỉ định bởi admin, sau đó xóa các bộ đếm.

Tính chất quan trọng: reserve trong bất biến luôn được tính **trừ** PnL tích lũy, vì vậy `TakePnl` không di chuyển đường cong. Điều này phù hợp với quy ước CPMM.

## Ví dụ đã làm việc

Trạng thái pool:

* `coin_reserve = 1_000_000_000_000` (1.000.000 coin-side; 6 chữ số thập phân)
* `pc_reserve   = 2_000_000_000_000` (2.000.000 pc-side; 6 chữ số thập phân)
* Phí: `swap = 25/10_000` mặc định, `pnl = 3/10_000`.

Người dùng: `SwapBaseIn` đầu vào chính xác `1_000_000_000` coin (1.000 coin).

```
swap_fee        = ceil(1_000_000_000 * 25 / 10_000)    = 2_500_000
amount_after_fee =                                      997_500_000

amount_out = amount_after_fee * pc_reserve
           / (coin_reserve + amount_after_fee)
           = 997_500_000 * 2_000_000_000_000
           / (1_000_000_000_000 + 997_500_000)
           ≈ 1_995_015_009  (1.995,015 pc)

// Của phí swap 2_500_000:
pnl_share = 2_500_000 * 3 / 25  = 300_000    (đi đến giao thức qua need_take_pnl_coin)
lp_share  = 2_500_000 * 22 / 25 = 2_200_000  (ở lại trong coin_reserve)

new coin_reserve = 1_000_000_000_000 + 1_000_000_000                 = 1_001_000_000_000
                   (trong đó 300_000 là PnL tích lũy)
  curve coin_reserve = 1_001_000_000_000 − 300_000 = 1_000_999_700_000
new pc_reserve   = 2_000_000_000_000 − 1_995_015_009                 ≈ 1_998_004_984_991

k' = curve_coin_reserve * new_pc_reserve
   ≈ 2.000_002_701E24
k  = 1_000_000_000_000 * 2_000_000_000_000
   = 2.0E24
k' > k   ✓
```

Phần LP (`2_200_000`) không được tách riêng ở bất kỳ đâu — nó đơn giản là phần dư tăng `k'`.

## Quy tắc độ chính xác

* Phép nhân reserve sử dụng `u128`; phép chia cuối cùng làm tròn về phía không.
* `swap_fee` làm tròn lên (vì vậy pool không tính phí thấp).
* `amount_in` cho `SwapBaseOut` làm tròn lên (vì vậy người dùng không trả ít).
* Pool có tỷ lệ reserve cực đoan có thể gặp `ZeroTradingTokens` trên đầu vào rất nhỏ; quy ước tương tự như CPMM.

## Hạn chế so với CPMM

* Reserve của AMM v4 hiện tại chỉ từ vault, vì vậy bạn **có thể** báo giá trực tiếp từ số dư vault (trừ `need_take_pnl_*`) — yêu cầu trước đó để thêm các số tiền `open_orders.free` / `open_orders.locked` không còn áp dụng. Báo giá SDK / API vẫn là tùy chọn đơn giản nhất.
* AMM v4 không công khai TWAP có cấu trúc trên chuỗi. Các người tiêu dùng bên ngoài muốn giá được hỗ trợ bởi AMM-v4 phải tính toán nó từ nhật ký giao dịch.
* Token-2022 không được hỗ trợ.

## Tiếp theo

* [`products/amm-v4/instructions`](/vi/products/amm-v4/instructions) — nơi `SwapBaseIn`, `Deposit`, v.v. được kết nối.
* [`products/amm-v4/fees`](/vi/products/amm-v4/fees) — cơ chế phí đầy đủ, chi tiết `TakePnl`.
* [`algorithms/constant-product`](/vi/algorithms/constant-product) — phép tính dẫn xuất được chia sẻ.

Nguồn:

* [Mã nguồn chương trình Raydium AMM — `raydium-io/raydium-amm`](https://github.com/raydium-io/raydium-amm)
* Mô-đun `Liquidity` của Raydium SDK v2
