advanced 75 min

AMM architecture & logic

The Automated Market Maker — pool / pseudo-account design, LP tokens, and the constant-product maths.

Prerequisites

Complete these before starting this module:

What you'll learn

  • Describe the ltAMM entry, the pseudo-account and LP tokens.
  • Apply the constant-product formula and swap maths.
  • Locate the AMM code (helpers, transactors).
Complete this module by self-assessment and a quiz. Jump to assessment

Introduction

≈75 min · Advanced · builds on Transaction ordering

The final phase is about extending the protocol, and we start with one of its richest features, the AMM. In this module you'll learn the ltAMM ledger entry, the pseudo-account that holds a pool with no signing key, LP tokens, and the constant-product math that prices every swap. It's DeFi, built natively into the ledger.

Core Concepts

In brief: what an AMM is, and how XRPL's built-in one differs from a standalone AMM.

What is an AMM?

An Automated Market Maker is a decentralized exchange mechanism that uses a mathematical formula to price assets. Instead of matching buyers and sellers through an order book, AMMs use liquidity pools where:

  1. Liquidity Providers (LPs) deposit pairs of assets into pools
  2. Traders swap one asset for another against the pool
  3. Prices are determined algorithmically based on pool balances
  4. Fees are distributed to LPs proportionally to their ownership

XRPL AMM vs. Traditional AMMs

Feature Traditional AMM (Uniswap v2) XRPL AMM
Formula x * y = k x * y = k (same)
Fee Model Fixed fee Governance-voted fee
Fee Discount None Auction slot mechanism
Order Book Separate Integrated with CLOB
LP Tokens ERC-20 Native XRPL tokens
Pathfinding External Native integration

The ltAMM Ledger Entry

In brief: the on-ledger object that stores a pool's assets and settings.

Every AMM pool is represented by an ltAMM ledger entry (type 0x0079). This entry stores the pool configuration, current state, and governance data.

Location: include/xrpl/protocol/detail/ledger_entries.macro

Structure

LEDGER_ENTRY(ltAMM, 0x0079, AMM, ({
    {sfAccount,           REQUIRED},  // Pseudo-account ID
    {sfTradingFee,        DEFAULT},   // Trading fee, units of 1/100,000 (1000 = 1%)
    {sfVoteSlots,         OPTIONAL},  // Array of up to 8 VoteEntry objects
    {sfAuctionSlot,       OPTIONAL},  // Auction slot holder and settings
    {sfLPTokenBalance,    REQUIRED},  // Total outstanding LP tokens
    {sfAsset,             REQUIRED},  // First asset issue
    {sfAsset2,            REQUIRED},  // Second asset issue
    {sfOwnerNode,         REQUIRED},  // Directory linkage
    {sfPreviousTxnID,     OPTIONAL},  // Last transaction hash
    {sfPreviousTxnLgrSeq, OPTIONAL},  // Last transaction ledger sequence
}))

Field Details

sfAccount - The pseudo-account that holds pool assets. This is a special account created during AMMCreate with no signing keys.

sfTradingFee - Current trading fee in units of 1/100,000 (0.001% per unit, so the maximum 1000 = 1%). Careful: these are not standard basis points (1 bp = 0.01%). Determined by weighted LP voting.

sfLPTokenBalance - Total LP tokens outstanding. Represents total pool ownership claims.

sfAsset / sfAsset2 - The two assets in the pool. Always ordered: Asset < Asset2 (lexicographic ordering ensures uniqueness).

Keylet Access

// Get AMM keylet from two issues
Keylet keylet::amm(Issue const& issue1, Issue const& issue2);

// The issues are automatically ordered internally
// keylet::amm(USD/Gateway, XRP) == keylet::amm(XRP, USD/Gateway)

Location: include/xrpl/protocol/Keylet.h

Pseudo-Account Architecture

In brief: a keyless account that actually holds the pool's funds.

Each AMM pool operates through a pseudo-account - a special XRPL account with unique properties.

Characteristics

  1. No Master Key: The account's master key is disabled (cannot sign transactions)
  2. AMM-Controlled: Only AMM transactors can modify its state
  3. Holds Assets: Contains trustlines for both pool assets and LP tokens
  4. Identified by sfAMMID: AccountRoot contains sfAMMID field linking to ltAMM

Creation Process (in AMMCreate)

Security Model

The pseudo-account design ensures:

  • No External Control: Without signing keys, no one can directly transact from this account
  • Protocol-Only Access: Only AMM transactors (AMMDeposit, AMMWithdraw, etc.) can modify balances
  • Trustline Isolation: Pool assets are isolated in dedicated trustlines

Key idea. An AMM pool is owned by a pseudo-account with no usable signing key. No one can move the pool's funds directly; only the AMM transactions can.

LP Token Design

In brief: the tokens that represent each provider's share of the pool.

LP (Liquidity Provider) tokens represent fractional ownership of pool assets. XRPL implements them as native tokens with a special currency code.

Currency Code Structure

// LP token currency = 0x03 + SHA512Half(sorted asset currencies)

// Construction:
Currency lptCurrency;
lptCurrency[0] = 0x03;  // AMM LP token marker

// Remaining 19 bytes = truncated hash of sorted currencies
auto const hash = sha512Half(
    std::min(currency1, currency2),
    std::max(currency1, currency2)
);
std::memcpy(&lptCurrency[1], hash.data(), 19);

Location: src/libxrpl/ledger/helpers/AMMHelpers.cpp

LP Token Properties

Property Value
Currency Code 0x03 prefix + 19-byte hash
Issuer AMM pseudo-account
Precision 16 significant digits
Transferable Yes (standard trustlines)
Tradeable Yes (can be traded on DEX)

Initial LP Token Calculation

When a pool is created, the initial LP token balance is:

LPT_initial = sqrt(Amount1 * Amount2)

This geometric mean ensures the initial LP tokens represent equal value from both assets.

Code Reference: src/libxrpl/ledger/helpers/AMMHelpers.cpp:5-17

STAmount ammLPTokens(
    STAmount const& asset1,
    STAmount const& asset2,
    Issue const& lptIssue)
{
    // sqrt(asset1 * asset2)
    auto const tokens = root2(asset1 * asset2);
    return toSTAmount(lptIssue, tokens);
}

VoteSlots: Fee Governance

In brief: LPs vote the pool's fee, weighted by their share.

LPs can vote on the trading fee through the sfVoteSlots array. This implements decentralized governance for pool parameters.

Purpose and Use Cases

Why Governance-Voted Fees?

Unlike traditional AMMs with fixed fees (e.g., Uniswap's 0.3%), XRPL allows LPs to collectively decide the optimal fee for their pool. This enables:

  • Market-Driven Optimization: Volatile pairs may need higher fees; stable pairs can have lower fees
  • Competitive Positioning: LPs can adjust fees to attract more trading volume
  • Risk Compensation: Higher fees for riskier asset pairs

When to Use AMMVote:

  • You hold LP tokens and want to influence the pool's trading fee
  • You believe the current fee is too high (reducing volume) or too low (not compensating risk)
  • You want to align the pool's economics with market conditions

Structure

// VoteEntry fields
struct VoteEntry {
    AccountID Account;     // Voter's account
    uint16_t FeeVal;       // Proposed fee, units of 1/100,000 (0-1000)
    uint32_t VoteWeight;   // LP token ownership share of the pool
};

// Up to 8 VoteEntry objects per AMM
constexpr std::uint16_t VOTE_MAX_SLOTS = 8;

Voting Mechanics

  1. Weight Calculation: Vote weight = (LP balance / Total LP tokens) * 100000
  2. Fee Calculation: TradingFee = sum(weight_i * fee_i) / sum(weight_i)
  3. Slot Management: If 8 slots full, new voter must have higher weight than lowest existing voter
  4. Instant Effect: Fee changes immediately when votes are cast or LP balances change

Example Scenario

The VoteSlots weighted vote: Alice, Bob, Carol, and Dave hold 50, 30, 15, and 5 percent of the pool and propose fees of 0.3, 0.5, 0.2, and 0.4 percent (TradingFee values 300, 500, 200, 400), producing a weighted trading fee of 0.35 percent, TradingFee 350.

What happens when Eve (with 2,000 LP tokens) wants to vote?

  • Eve has more LP than Dave (500), so she can replace Dave's slot
  • New fee recalculates with Eve's vote instead of Dave's

AuctionSlot: Discounted Trading

In brief: rent the zero-fee slot by burning LP tokens.

The auction slot mechanism allows LPs to bid for reduced trading fees during a 24-hour period.

Purpose and Use Cases

Why Auction Slots?

The auction slot creates a market mechanism where those who benefit most from low fees pay for that privilege. This is particularly valuable for:

  • Arbitrage Bots: Need low fees to capture small price discrepancies
  • High-Frequency Traders: Volume traders where fees significantly impact profitability
  • Market Makers: Entities providing liquidity across multiple venues

When to Use AMMBid:

  • You plan to execute many trades against this pool in the next 24 hours
  • The fee savings from 0% trading outweigh the LP token cost
  • You want to authorize trading bots to use your discounted fee

Economic Design:

  • The auction creates revenue for LPs (bid payments are partially burned)
  • Competition for the slot ensures fair market pricing
  • Time decay prevents slot hoarding at low prices

Structure

// AuctionSlot fields
struct AuctionSlot {
    AccountID Account;           // Current slot holder
    NetClock::time_point Expiration;  // Slot expiration (24h from bid)
    uint16_t DiscountedFee;      // Fee paid by holder (typically 0)
    STAmount Price;              // Bid amount in LP tokens
    std::vector<AccountID> AuthAccounts;  // Up to 4 authorized accounts
};

Auction Mechanics

Time Division:

  • 24-hour slot divided into 20 intervals (1.2 hours each)
  • Three states: Empty, Occupied (>=5% remaining), Tailing (<5% remaining)

Bidding Formula:

min_bid = current_price * 1.05 + min_slot_price

// Where min_slot_price considers time decay:
// As time passes, minimum bid decreases

Refund Mechanism:

refund_to_previous = (1 - time_fraction_used) * previous_price
burned = new_bid - refund

Example Scenario

The AuctionSlot scenario: the slot starts empty at a 100 LP minimum bid, Alice takes it for 150 LP and trades at zero fee for 24 hours, then Bob outbids with 200 LP after 12 hours, Alice gets 75 LP refunded, and the remaining 125 LP are burned for all LPs.

Benefits

  • Slot Holder: Trades with discounted fee (often 0%)
  • AuthAccounts: Up to 4 additional accounts can use discounted fee
  • All LPs: LP tokens paid are partially burned, increasing LP token value

VoteSlots vs AuctionSlot: Key Differences

In brief: two governance gadgets, side by side.

Aspect VoteSlots AuctionSlot
Purpose Set trading fee for everyone Get discounted fee for yourself
Slots Up to 8 Exactly 1
Cost Free (just hold LP tokens) Pay LP tokens to win
Duration Permanent (until vote changes) 24 hours
Benefit Influence pool economics Personal trading advantage
Who benefits All pool users Slot holder + 4 authorized
Transaction AMMVote AMMBid

Integration with Pathfinding

In brief: AMM offers compete with the order book on quality.

AMM pools don't just exist in isolation - they're deeply integrated with XRPL's pathfinding engine (covered in detail in AMM Pathfinding).

Key Integration Points

  1. AMMLiquidity: Generates synthetic offers from AMM pools
  2. AMMOffer: Represents an AMM-backed offer in payment paths
  3. Quality Matching: AMM offers compete with CLOB offers on price

Dual Liquidity Model

The dual liquidity model: a payment request enters the pathfinding engine, where CLOB offers and synthetic AMM offers compete on quality, and the best execution path wins.

AMM Amendment

In brief: the feature flags that switched all of this on.

The AMM feature is controlled by the featureAMM amendment.

Location: include/xrpl/protocol/detail/features.macro

XRPL_FEATURE(AMM, Supported::yes, VoteBehavior::DefaultNo)
Amendment Purpose
featureAMM Core AMM functionality
fixUniversalNumber Required precision improvements
fixAMMv1_1 Rounding bug fixes
fixAMMv1_2 Additional fixes
fixAMMv1_3 Precision loss compensation
fixAMMOverflowOffer Offer generation overflow fix
featureAMMClawback Asset issuer clawback support

Checking AMM Availability

// From AMMCore.cpp
bool ammEnabled(Rules const& rules) {
    return rules.enabled(featureAMM) &&
           rules.enabled(fixUniversalNumber);
}

Both amendments must be active for AMM functionality to work.

References to Source Code

Cross-References

  • The Transactor architecture module (transaction processing phases)
  • the Ledger architecture & data structures module - Ledger entry types
  • The Amendments, overview & architecture module (feature activation)

AMM Logic

In brief: the mathematics: invariant, swaps, LP tokens, fees, precision.

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/libxrpl/ledger/helpers/AMMHelpers.cpp and AMMHelpers.h

The Constant Product Formula

In brief: x times y stays k, and price is the ratio.

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

In brief: exact in and exact out, with the fee in the right place.

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: include/xrpl/ledger/helpers/AMMHelpers.h:443-505

Example:

Pool: 1000 XRP / 2000 USD
Trading Fee: 0.3% (tfee = 300, since the TradingFee field's 1000 = 1%)
Input: 100 XRP

in_fee = 100 * (1 - 300/100000) = 100 * 0.997 = 99.7 XRP
out = 2000 - (1000 * 2000) / (1000 + 99.7)
out = 2000 - 2000000 / 1099.7
out = 2000 - 1818.68
out = 181.32 USD

Swap Asset Out (swapAssetOut)

Given a desired output amount, calculate the required input.

Formula:

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

Location: include/xrpl/ledger/helpers/AMMHelpers.h:517-578

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

In brief: minting and burning shares of the pool.

Initial LP Tokens (ammLPTokens)

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

LPT = sqrt(Asset1 * Asset2)

Location: src/libxrpl/ledger/helpers/AMMHelpers.cpp:5-17

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: include/xrpl/ledger/helpers/AMMHelpers.h:131-187

Assets Required for LP Tokens (ammAssetIn)

Calculate how much asset is needed for specific LP tokens.

Equation 4 (inverse of Equation 3):

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:

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

In brief: how the trading fee enters every formula.

Fee Multipliers

Constants:

constexpr std::uint32_t AUCTION_SLOT_FEE_SCALE_FACTOR = 100000;

Fee Ranges

  • Minimum: 0 (no fee)
  • Maximum: TradingFee 1000 (= 1%)
  • Typical: TradingFee 30-100 (= 0.03% - 0.1%)

Auction Slot Discount

Auction slot holders pay reduced fees:

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

In brief: spot price, quality, and CLOB comparability.

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: include/xrpl/ledger/helpers/AMMHelpers.h:310-420

Precision and Overflow Handling

In brief: Number, rounding rules, and invariant checks.

Number Type

XRPL uses a custom Number type for AMM calculations:

// 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

// 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:

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

In brief: the formulas with real numbers plugged in.

Example 1: Simple Swap

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

References to Source Code

Cross-References

  • AMM Architecture - Data structures
  • AMM Transactions - How formulas are used
  • AMM Pathfinding - Quality matching in practice

Summary

This module opened up the Automated Market Maker built into the ledger. You learned the ltAMM ledger entry that stores a pool, the pseudo-account that holds the pool's funds with no usable signing key, the LP tokens that represent each provider's share, and the constant-product maths that prices every swap, along with the vote and auction slots for fee governance and discounts.

To remember:

  • The ltAMM entry stores: the two assets, the LP token issue, TradingFee, VoteSlots, AuctionSlot
  • Pool funds sit in a pseudo-account with no usable signing key: only AMM transactions can move them
  • LP tokens are proportional shares; the initial issue is the geometric mean sqrt(x * y)
  • Pricing is constant-product x * y = k; trading fees accrue into the pool
  • VoteSlots: LPs vote the trading fee (holdings-weighted); AuctionSlot: discounted trading, paid in LP tokens
  • keylet::amm(asset, asset2) is order-independent
  • Code: src/libxrpl/tx/transactors/dex + include/xrpl/protocol/AMMCore.h
  • Watch out: nobody can rescue funds sent directly to the pseudo-account; only protocol paths touch the pool

Next up. You know the AMM's anatomy; now watch it trade. Next: the AMM transactions and its integration with pathfinding.

Assignments

0 of 2 complete

Unlocks

Finishing this module opens up:

XRPL Academy © 2026