> For the complete documentation index, see [llms.txt](https://docs.xrpl-commons.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.xrpl-commons.org/core-dev-bootcamp/module09bis/amm-logic.md).

# AMM Logic

[Back to AMM: Automated Market Maker](/core-dev-bootcamp/module09bis.md)

***

## Introduction

The logic behind XRPL's AMM is critical for understanding how prices are determined, LP tokens are calculated, and trades execute. This chapter provides a deep dive into the constant product formula, swap calculations, LP token minting/burning, and the precision handling that ensures numerical correctness.

**Location:** `src/xrpld/app/misc/AMMHelpers.cpp` and `AMMHelpers.h`

## The Constant Product Formula

### Core Invariant

XRPL's AMM uses the **constant product** formula, popularized by Uniswap:

```
x * y = k
```

Where:

* `x` = Balance of Asset 1
* `y` = Balance of Asset 2
* `k` = Constant product (invariant)

### How It Works

After every trade, the product of the two asset balances must remain constant (or increase slightly due to fees):

```
Before trade: A * B = k
After trade:  A' * B' >= k
```

The inequality (`>=`) accounts for trading fees, which slightly increase `k` over time, benefiting liquidity providers.

### Price Determination

The **spot price** of Asset1 in terms of Asset2 is:

```
Price(Asset1) = B / A
```

As traders buy Asset1:

* A decreases (removed from pool)
* B increases (added to pool)
* Price of Asset1 increases (B/A grows)

This creates automatic price discovery through supply and demand.

## Swap Formulas

### Swap Asset In (swapAssetIn)

Given an input amount, calculate the output amount.

**Formula:**

```
out = B - (A * B) / (A + in_fee)
```

Where:

```
in_fee = in * (1 - tradingFee / 100000)
```

**Location:** `src/xrpld/app/misc/AMMHelpers.h:443-505`

```cpp
template <typename TIn, typename TOut>
TOut swapAssetIn(
    TAmounts<TIn, TOut> const& pool,  // {A, B}
    TIn const& assetIn,               // Input amount
    std::uint16_t tfee)               // Trading fee
{
    // Calculate fee-adjusted input
    auto const in_fee = assetIn * feeMult(tfee);

    // Apply constant product formula
    // out = B - (A * B) / (A + in_fee)
    auto const out = pool.out -
        divide(pool.in * pool.out, pool.in + in_fee, ...);

    return out;
}
```

**Example:**

```
Pool: 1000 XRP / 2000 USD
Trading Fee: 0.3% (30 basis points)
Input: 100 XRP

in_fee = 100 * (1 - 30/100000) = 100 * 0.9997 = 99.97 XRP
out = 2000 - (1000 * 2000) / (1000 + 99.97)
out = 2000 - 2000000 / 1099.97
out = 2000 - 1818.23
out = 181.77 USD
```

### Swap Asset Out (swapAssetOut)

Given a desired output amount, calculate the required input.

**Formula:**

```
in = ((A * B) / (B - out) - A) / (1 - fee)
```

**Location:** `src/xrpld/app/misc/AMMHelpers.h:517-578`

```cpp
template <typename TIn, typename TOut>
TIn swapAssetOut(
    TAmounts<TIn, TOut> const& pool,  // {A, B}
    TOut const& assetOut,             // Desired output
    std::uint16_t tfee)               // Trading fee
{
    // Reverse constant product calculation
    auto const in = divide(
        pool.in * pool.out / (pool.out - assetOut) - pool.in,
        feeMult(tfee),
        ...);

    return in;
}
```

### Rounding Strategy

**Critical Design Decision:** Rounding always favors the AMM pool.

* `swapAssetIn`: Output is rounded **down** (less tokens out)
* `swapAssetOut`: Input is rounded **up** (more tokens required)

This ensures the pool never loses value due to rounding errors.

## LP Token Calculations

### Initial LP Tokens (ammLPTokens)

When creating a pool, initial LP tokens are the geometric mean:

```
LPT = sqrt(Asset1 * Asset2)
```

**Location:** `src/xrpld/app/misc/AMMHelpers.cpp:5-17`

```cpp
STAmount ammLPTokens(
    STAmount const& asset1,
    STAmount const& asset2,
    Issue const& lptIssue)
{
    // Geometric mean ensures equal value contribution
    auto const tokens = root2(asset1 * asset2);
    return toSTAmount(lptIssue, tokens);
}
```

**Why Geometric Mean?**

* Prevents manipulation by depositing unequal values
* Initial depositor cannot "steal" value from pool
* LP tokens represent true fractional ownership

### LP Tokens for Deposit (lpTokensOut)

Calculate LP tokens received for depositing assets.

#### Proportional Deposit (Both Assets)

When depositing proportionally (same ratio as pool):

```
LPT_out = LPT_total * (deposit / balance)
```

No trading fee charged for proportional deposits.

#### Single Asset Deposit

**Equation 3** from AMMHelpers.cpp:

```
t = T * [(b/B - (sqrt(f2^2 - b/(B*f1)) - f2)) / (1 + sqrt(f2^2 - b/(B*f1)) - f2)]
```

Where:

* `t` = LP tokens received
* `T` = Total LP tokens
* `b` = Deposit amount
* `B` = Pool balance of deposited asset
* `f1` = 1 - tradingFee
* `f2` = (1 - tradingFee/2) / f1

**Location:** `src/xrpld/app/misc/AMMHelpers.h:131-187`

```cpp
template <typename T>
STAmount lpTokensOut(
    STAmount const& asset,      // Pool balance B
    STAmount const& lptAMMBalance,  // Total LP tokens T
    T const& depositAmount,     // Deposit amount b
    std::uint16_t tfee)         // Trading fee
{
    // Apply Equation 3
    auto const f1 = feeMult(tfee);
    auto const f2 = feeMultHalf(tfee) / f1;
    auto const ratio = depositAmount / asset;

    auto const sqrt_term = root2(f2 * f2 - ratio / f1) - f2;
    auto const lpTokens = lptAMMBalance * (ratio - sqrt_term) / (1 + sqrt_term);

    return lpTokens;
}
```

### Assets Required for LP Tokens (ammAssetIn)

Calculate how much asset is needed for specific LP tokens.

**Equation 4** (inverse of Equation 3):

```cpp
template <typename T>
T ammAssetIn(
    STAmount const& asset,
    STAmount const& lptAMMBalance,
    STAmount const& lpTokens,
    std::uint16_t tfee)
{
    // Inverse calculation to find required deposit
    // for desired LP tokens output
}
```

### LP Tokens to Burn (lpTokensIn)

Calculate LP tokens needed for a specific withdrawal.

**Equation 7:**

```
t = T * (c - sqrt(c^2 - 4*R)) / 2
```

Where:

* `t` = LP tokens to burn
* `T` = Total LP tokens
* `R` = withdrawal / poolBalance
* `c` = R \* fee + 2 - fee

### Assets for LP Token Burn (ammAssetOut)

Calculate assets received for burning LP tokens.

**Equation 8:**

```cpp
template <typename T>
T ammAssetOut(
    STAmount const& asset,
    STAmount const& lptAMMBalance,
    STAmount const& lpTokens,
    std::uint16_t tfee)
{
    // Calculate withdrawal amount for given LP tokens
}
```

## Fee Calculations

### Fee Multipliers

```cpp
// Full fee multiplier: 1 - fee
Number feeMult(std::uint16_t tfee)
{
    return 1 - Number(tfee) / AUCTION_SLOT_FEE_SCALE_FACTOR;
}

// Half fee multiplier: 1 - fee/2 (for proportional operations)
Number feeMultHalf(std::uint16_t tfee)
{
    return 1 - Number(tfee) / (2 * AUCTION_SLOT_FEE_SCALE_FACTOR);
}

// Get fee as decimal
Number getFee(std::uint16_t tfee)
{
    return Number(tfee) / AUCTION_SLOT_FEE_SCALE_FACTOR;
}
```

**Constants:**

```cpp
constexpr std::uint32_t AUCTION_SLOT_FEE_SCALE_FACTOR = 100000;
```

### Fee Ranges

* **Minimum:** 0 (no fee)
* **Maximum:** 1000 basis points (1%)
* **Typical:** 30-100 basis points (0.03% - 0.1%)

### Auction Slot Discount

Auction slot holders pay reduced fees:

```cpp
std::uint16_t getTradingFee(
    ReadView const& view,
    SLE const& ammSle,
    AccountID const& account)
{
    // Check if account is slot holder or authorized
    if (isAuctionSlotHolder(ammSle, account))
        return ammSle[sfAuctionSlot].getFieldU16(sfDiscountedFee);  // Usually 0

    return ammSle.getFieldU16(sfTradingFee);
}
```

## Quality and Price Calculations

### Spot Price Quality

The "quality" represents the exchange rate for offers:

```
Quality = TakerGets / TakerPays
```

For AMM, the spot price quality is:

```
SpotQuality = PoolOut / PoolIn
```

### Quality Matching with CLOB

The pathfinding engine needs AMM offers that match CLOB quality.

**Location:** `src/xrpld/app/misc/AMMHelpers.h:310-420`

```cpp
template <typename TIn, typename TOut>
std::optional<TAmounts<TIn, TOut>>
changeSpotPriceQuality(
    TAmounts<TIn, TOut> const& pool,
    Quality const& quality,          // Target quality (from CLOB)
    std::uint16_t tfee,
    Rules const& rules,
    beast::Journal j)
{
    // Solve quadratic equation to find offer amounts
    // that result in pool having target spot price quality
    // after the trade

    // This enables AMM to compete with CLOB offers
}
```

## Precision and Overflow Handling

### Number Type

XRPL uses a custom `Number` type for AMM calculations:

```cpp
// Number provides arbitrary precision arithmetic
// Essential for avoiding overflow in large pool calculations

Number result = root2(asset1 * asset2);
```

### Precision Amendments

Several amendments improve precision handling:

| Amendment           | Fix                                       |
| ------------------- | ----------------------------------------- |
| fixUniversalNumber  | Required for AMM (precision improvements) |
| fixAMMv1\_1         | Rounding improvements                     |
| fixAMMv1\_3         | Precision loss compensation               |
| fixAMMOverflowOffer | Overflow in offer calculation             |

### Rounding Strategies

```cpp
// Round based on who should benefit
enum class Round {
    upward,    // Round up (more required from user)
    downward   // Round down (less given to user)
};

// Swaps: Round to favor pool
// Deposits: Round to favor pool
// Withdrawals: Round to favor pool
```

### Invariant Checking

After every operation, verify the pool invariant:

```cpp
bool checkInvariant(
    TAmounts<TIn, TOut> const& oldPool,
    TAmounts<TIn, TOut> const& newPool)
{
    // New product must be >= old product
    return (newPool.in * newPool.out) >= (oldPool.in * oldPool.out);
}
```

## Worked Examples

### Example 1: Simple Swap

```
Pool: 10,000 XRP / 20,000 USD
Fee: 0.3% (30 bps)
Swap: 500 XRP -> USD

Step 1: Apply fee
in_fee = 500 * (1 - 0.003) = 498.5 XRP

Step 2: Calculate output
k = 10000 * 20000 = 200,000,000
new_xrp = 10000 + 498.5 = 10498.5
new_usd = k / new_xrp = 200000000 / 10498.5 = 19050.45

out = 20000 - 19050.45 = 949.55 USD

Result: 500 XRP -> 949.55 USD
Effective rate: 1.899 USD/XRP
```

### Example 2: LP Token Minting

```
Pool: 10,000 XRP / 20,000 USD
Total LP Tokens: 14,142.13 (sqrt(10000 * 20000))
Deposit: 1,000 XRP + 2,000 USD (proportional)

Ratio = 1000/10000 = 0.1 (10%)
LP_out = 14142.13 * 0.1 = 1,414.21 LP tokens

New state:
- Pool: 11,000 XRP / 22,000 USD
- Total LP: 15,556.34
- Depositor owns: 1,414.21 / 15,556.34 = 9.09% of pool
```

### Example 3: Single Asset Deposit

```
Pool: 10,000 XRP / 20,000 USD
Total LP: 14,142.13
Fee: 0.3%
Deposit: 1,000 XRP only

Using Equation 3:
f1 = 1 - 0.003 = 0.997
f2 = (1 - 0.0015) / 0.997 = 1.0005
ratio = 1000 / 10000 = 0.1

sqrt_term = sqrt(1.0005^2 - 0.1/0.997) - 1.0005
         = sqrt(1.001 - 0.1003) - 1.0005
         = sqrt(0.9007) - 1.0005
         = 0.949 - 1.0005
         = -0.0515

LP_out = 14142.13 * (0.1 - (-0.0515)) / (1 + (-0.0515))
       = 14142.13 * 0.1515 / 0.9485
       = 2259.3 LP tokens

Note: Single asset deposit gets fewer LP tokens
due to implicit swap + fee
```

## Summary

The AMM mathematics ensure:

1. **Fair Pricing**: Constant product formula provides automatic price discovery
2. **LP Protection**: Geometric mean prevents initial deposit manipulation
3. **Fee Collection**: Trading fees increase pool value over time
4. **Numerical Safety**: Careful rounding always favors the pool
5. **CLOB Integration**: Quality matching enables fair competition

Understanding these formulas is essential for:

* Implementing AMM features
* Debugging price discrepancies
* Building AMM analytics tools
* Auditing pool behavior

## References to Source Code

* `src/xrpld/app/misc/AMMHelpers.cpp` - Core calculations
* `src/xrpld/app/misc/AMMHelpers.h` - Formula implementations
* `src/xrpld/app/misc/AMMCore.h` - Constants
* `src/libxrpl/basics/Number.cpp` - Precision arithmetic

## Cross-References

* [AMM Architecture](/core-dev-bootcamp/module09bis/amm-architecture.md) - Data structures
* [AMM Transactions](/core-dev-bootcamp/module09bis/amm-transactions.md) - How formulas are used
* [AMM Pathfinding](/core-dev-bootcamp/module09bis/amm-pathfinding.md) - Quality matching in practice


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.xrpl-commons.org/core-dev-bootcamp/module09bis/amm-logic.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
