advanced 75 min

AMM transactions & pathfinding

The seven AMM transaction types and how AMM liquidity is integrated into pathfinding alongside the order book.

Prerequisites

Complete these before starting this module:

What you'll learn

  • Walk the AMM transactors (Create, Deposit, Withdraw, Vote, Bid, Delete, Clawback).
  • Explain synthetic AMM offers and pathfinding integration.
  • Understand fee governance and auction slots.
Complete this module by self-assessment and a quiz. Jump to assessment

Introduction

≈75 min · Advanced · builds on AMM architecture & logic

Now let's put the AMM to work. In this module you'll walk the seven AMM transaction types (Create, Deposit, Withdraw, Vote, Bid, Delete, Clawback) and see how pool liquidity is woven into pathfinding through synthetic offers, alongside fee governance and auction slots. This is how the AMM actually trades.

Transaction Type Overview

In brief: the seven AMM transactions and what each one does.

Transaction Type Code Purpose
AMMCreate 35 (ttAMM_CREATE) Create new AMM pool
AMMDeposit 36 (ttAMM_DEPOSIT) Add liquidity to pool
AMMWithdraw 37 (ttAMM_WITHDRAW) Remove liquidity from pool
AMMVote 38 (ttAMM_VOTE) Vote on trading fee
AMMBid 39 (ttAMM_BID) Bid for auction slot
AMMDelete 40 (ttAMM_DELETE) Delete empty pool
AMMClawback 31 (ttAMM_CLAWBACK) Issuer clawback from pool

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

Key idea. AMM liquidity is not walled off from the order book: pathfinding sees it through synthetic offers, so a trade can route through pools and the order book together.

AMMCreate

In brief: spin up a new pool and mint its first LP tokens.

Creates a new AMM pool for a pair of assets.

Location: src/libxrpl/tx/transactors/dex/AMMCreate.cpp

Transaction Fields

Field Required Description
Amount Yes First asset to deposit
Amount2 Yes Second asset to deposit
TradingFee Yes Initial trading fee, units of 1/100,000 (0-1000, max = 1%)

preflight()

Static validation before ledger access:

preclaim()

Validation with ledger read access:

doApply()

Execution with ledger modifications:

Reserve Requirements

Creating an AMM requires reserve for:

  • 1 AMM pseudo-account
  • 2-3 trustlines (Asset1, Asset2, and potentially LP token)
  • 1 ltAMM ledger entry

AMMDeposit

In brief: add liquidity and receive LP tokens in return.

Adds liquidity to an existing AMM pool in exchange for LP tokens.

Location: src/libxrpl/tx/transactors/dex/AMMDeposit.cpp

Deposit Modes

AMMDeposit supports multiple modes controlled by flags:

Flag Required Fields Description
tfLPToken LPTokenOut Deposit proportional amounts for exact LP tokens
tfSingleAsset Amount Deposit single asset (trading fee charged)
tfTwoAsset Amount, Amount2 Deposit both with maximum constraints
tfOneAssetLPToken Amount, LPTokenOut Single asset for exact LP tokens
tfLimitLPToken Amount, EPrice Single asset with price limit
tfTwoAssetIfEmpty Amount, Amount2 Initialize empty pool (special case)

Transaction Fields

Field Required Description
Asset Yes First asset issue (identifies pool)
Asset2 Yes Second asset issue (identifies pool)
Amount Conditional Asset amount to deposit
Amount2 Conditional Second asset amount to deposit
LPTokenOut Conditional Minimum LP tokens to receive
EPrice Conditional Effective price limit

preflight()

NotTEC AMMDeposit::preflight(PreflightContext const& ctx)
{
    // 1. Validate flag combinations
    if (!validFlagCombination(ctx.tx.getFlags()))
        return temMALFORMED;

    // 2. Check required fields present for chosen mode
    // 3. Validate amount constraints

    return tesSUCCESS;
}

doApply() - Proportional Deposit

doApply() - Single Asset Deposit

AMMWithdraw

In brief: burn LP tokens to take your liquidity back out.

Removes liquidity from an AMM pool by burning LP tokens.

Location: src/libxrpl/tx/transactors/dex/AMMWithdraw.cpp

Withdrawal Modes

Flag Required Fields Description
tfLPToken LPTokenIn Burn LP tokens for proportional assets
tfSingleAsset Amount Withdraw single asset (trading fee charged)
tfTwoAsset Amount, Amount2 Withdraw specific amounts of both
tfOneAssetLPToken Amount, LPTokenIn Withdraw single asset for exact LP tokens
tfOneAssetWithdrawAll Amount Withdraw all LP as single asset
tfWithdrawAll (none) Withdraw all LP tokens proportionally

Key Validation

TER AMMWithdraw::preclaim(PreclaimContext const& ctx)
{
    // 1. Verify AMM exists
    // 2. Check account holds sufficient LP tokens
    // 3. Validate withdrawal won't violate minimum pool size
    // 4. For single asset: check pool can support withdrawal

    return tesSUCCESS;
}

doApply() - Proportional Withdrawal

AMMVote

In brief: casting a weighted fee vote, slot mechanics included.

Allows LP token holders to vote on the trading fee.

Location: src/libxrpl/tx/transactors/dex/AMMVote.cpp

Transaction Fields

Field Required Description
Asset Yes First asset issue (identifies pool)
Asset2 Yes Second asset issue (identifies pool)
TradingFee Yes Proposed fee, units of 1/100,000 (0-1000)

Voting Mechanics

Constants

constexpr std::uint16_t VOTE_MAX_SLOTS = 8;
constexpr std::uint32_t VOTE_WEIGHT_SCALE_FACTOR = 100000;

AMMBid

In brief: bidding LP tokens for the discounted auction slot.

Bid for the auction slot to receive discounted trading fees.

Location: src/libxrpl/tx/transactors/dex/AMMBid.cpp

Transaction Fields

Field Required Description
Asset Yes First asset issue (identifies pool)
Asset2 Yes Second asset issue (identifies pool)
BidMin No Minimum bid amount (LP tokens)
BidMax No Maximum bid amount (LP tokens)
AuthAccounts No Up to 4 accounts to authorize

Auction Slot States

  1. Empty: No current holder, minimum bid applies
  2. Occupied: Holder with >= 5% time remaining
  3. Tailing: Holder with < 5% time remaining (easier to outbid)

Bidding Logic

Slot Constants

constexpr std::uint32_t TOTAL_TIME_SLOT_SECS = 86400;      // 24 hours
constexpr std::uint16_t AUCTION_SLOT_TIME_INTERVALS = 20;   // 20 intervals
constexpr std::uint16_t AUCTION_SLOT_MAX_AUTH_ACCOUNTS = 4;

AMMDelete

In brief: removing an empty pool, in stages if needed.

Deletes an empty AMM pool (LP token balance = 0).

Location: src/libxrpl/tx/transactors/dex/AMMDelete.cpp

Transaction Fields

Field Required Description
Asset Yes First asset issue (identifies pool)
Asset2 Yes Second asset issue (identifies pool)

Deletion Process

Incremental Deletion

For pools with many trustlines (from LP token holders), deletion happens incrementally:

  • Each AMMDelete removes a limited number of trustlines
  • Transaction returns tecINCOMPLETE if more remain
  • Submitter must retry until fully deleted

AMMClawback

In brief: issuer clawback reaching into pool positions.

Allows asset issuers to clawback their tokens from AMM pools.

Location: src/libxrpl/tx/transactors/dex/AMMClawback.cpp

Prerequisites

  • featureAMMClawback amendment must be enabled
  • Caller must be the issuer of the asset being clawed back
  • Issuer must have lsfAllowTrustLineClawback flag set

Transaction Fields

Field Required Description
Holder Yes LP account to clawback from
Asset Yes Asset to clawback
Asset2 Yes Other asset in pool
Amount No Specific amount (or all if omitted)

Clawback Process

TER AMMClawback::doApply()
{
    // 1. Calculate LP tokens to burn (proportional to clawback)
    // 2. Burn LP tokens from holder
    // 3. Withdraw clawback amount to issuer
    // 4. Withdraw proportional other asset to holder
    // 5. Update pool state

    return tesSUCCESS;
}

Error Codes

In brief: the tec and tem codes specific to AMM transactions.

AMM transactions can return specific error codes:

Code Meaning
tecAMM_BALANCE Insufficient pool balance
tecAMM_FAILED General AMM operation failure
tecAMM_FAILED_BID Bid too low
tecAMM_FAILED_DEPOSIT Deposit constraints not met
tecAMM_FAILED_VOTE Vote failed (weight too low)
tecAMM_FAILED_WITHDRAW Withdrawal constraints not met
tecAMM_INVALID_TOKENS Invalid LP token operation
tecAMM_NOT_EMPTY Cannot delete non-empty pool
tecINCOMPLETE Deletion in progress

References to Source Code

Cross-References

  • The Transactor architecture module (transaction processing phases)
  • AMM Architecture - Data structures and pool design
  • AMM Logic - Formulas used in deposit/withdraw

Pathfinding Integration

In brief: how AMM liquidity joins payment routing.

One of XRPL's unique features is the deep integration between AMM pools and the pathfinding engine. Unlike other blockchains where AMM and order book liquidity are separate, XRPL's pathfinding engine can route payments through both CLOB offers and AMM pools, automatically selecting the best execution path.

This chapter explores how AMM offers are generated, how they compete with CLOB offers, and the algorithms that ensure optimal payment routing.

Architecture Overview

In brief: the components between a payment and the pool.

Dual Liquidity Model

The pathfinding engine with concrete numbers: the order book quotes qualities 2.00 to 2.02 while the AMM pool quotes a calculated 2.05, and the best execution path selection takes the cheaper book offers first.

Key Components

Component Location Purpose
AMMLiquidity src/libxrpl/tx/paths/AMMLiquidity.cpp Generate synthetic offers
AMMOffer src/libxrpl/tx/paths/AMMOffer.cpp Represent AMM offers
AMMContext include/xrpl/tx/transactors/dex/AMMContext.h Track AMM state during payment
BookStep src/libxrpl/tx/paths/BookStep.cpp Integrate AMM with order book

AMMContext: State Management

In brief: per-payment bookkeeping and the iteration cap.

The AMMContext class tracks AMM usage during payment execution.

Location: include/xrpl/tx/transactors/dex/AMMContext.h

Iteration Limit

The 30-iteration limit prevents:

  • Infinite loops in complex path finding
  • Excessive computation for large payments
  • Potential DoS through pathfinding abuse

AMMLiquidity: Offer Generation

In brief: building the synthetic offer that matches the book.

The AMMLiquidity class generates synthetic offers from AMM pools.

Location: src/libxrpl/tx/paths/AMMLiquidity.cpp

Offer Generation Strategies

Single Path Mode

When processing a single payment path, AMM offers are sized to match CLOB quality:

Multi-Path Mode

For payments using multiple paths, Fibonacci sequence sizing prevents over-concentration:

AMMOffer: Synthetic Offer Representation

In brief: an offer object that exists only in memory.

The AMMOffer class represents an AMM-backed offer in the pathfinding system. Unlike CLOB offers which are stored on the ledger, AMMOffers are created dynamically during payment execution.

Location: src/libxrpl/tx/paths/AMMOffer.cpp

When Are AMMOffers Created?

AMMOffers are not ledger objects - they are synthetic, ephemeral offers generated on-the-fly:

The AMMOffer lifecycle in six steps: a payment triggers BookStep, AMMLiquidity::getOffer builds an in-memory offer from pool balances to beat the best CLOB quality, the offer competes, consume applies the swap in the sandbox, and a fresh offer is generated for any remainder.

Key Insight: AMMOffers Are Ephemeral

CLOB Offer AMMOffer
Stored on ledger Created in memory
Persists until filled/cancelled Exists only during payment execution
Has explicit size Size calculated dynamically
Fixed quality Quality adapts to pool state
Created by OfferCreate tx Created by AMMLiquidity::getOffer()

How AMMOffers Are Sized

The size of an AMMOffer depends on the context:

Single-Path Mode:

// Match the best CLOB quality
auto amounts = changeSpotPriceQuality(pool, clobQuality, fee);
// AMMOffer is sized so that AFTER the trade,
// the pool's new spot price equals the CLOB quality

Multi-Path Mode:

// Use Fibonacci sequence to avoid over-consumption
// Iteration 0: 5/20000 of pool (0.025%)
// Iteration 1: 8/20000 of pool (0.04%)
// Iteration 2: 13/20000 of pool (0.065%)
// ... growing offers ensure gradual consumption

Structure

Quality Calculation

Quality AMMOffer::quality() const
{
    // Quality = out / in (how much you get per unit spent)
    return Quality(amounts_.out / amounts_.in);
}

Limiting Offers

When the payment doesn't need the full offer:

Consuming Offers

void AMMOffer::consume()
{
    // Mark as consumed
    consumed_ = true;

    // Update balances (for next iteration)
    balances_.in += amounts_.in;
    balances_.out -= amounts_.out;

    // Verify invariant
    assert(checkInvariant());
}

Integration with BookStep

In brief: where AMM and CLOB offers actually compete.

The BookStep class handles order book traversal, including AMM integration.

Location: src/libxrpl/tx/paths/BookStep.cpp

Processing Order

Quality Competition

AMM and CLOB offers compete purely on quality (exchange rate):

If AMM quality >= CLOB quality:
    Use AMM offer
Else:
    Use CLOB offer

This ensures best execution regardless of liquidity source.

Multi-Path Payment Example

In brief: one payment split across book and pool.

Scenario

Payment: 10,000 XRP -> USD Available liquidity:

  • CLOB: 5,000 XRP @ 2.00 USD/XRP
  • CLOB: 3,000 XRP @ 1.98 USD/XRP
  • AMM Pool: 100,000 XRP / 200,000 USD (spot: 2.00)

Execution

Flow Diagram

The BookStep selection loop: compute gathers CLOB offers and the synthetic AMM offer, compares their qualities, consumes whichever is better, and loops until the payment is complete.

Performance Considerations

In brief: what all this costs per payment.

Iteration Limits

// Maximum AMM iterations per payment
constexpr std::uint8_t MaxIterations = 30;

Why 30?

  • Balances payment quality with computation cost
  • Prevents pathfinding abuse
  • Sufficient for most payment sizes

Quality Caching

// Cache quality calculations to avoid recomputation
Quality cachedQuality_;
bool qualityValid_ = false;

Quality getQuality() {
    if (!qualityValid_) {
        cachedQuality_ = computeQuality();
        qualityValid_ = true;
    }
    return cachedQuality_;
}

Balance Snapshots

// Snapshot balances at start to avoid repeated ledger reads
TAmounts<TIn, TOut> initialBalances_;

AMMLiquidity(...) {
    initialBalances_ = fetchBalances(view);
}

Edge Cases

In brief: empty pools, one-sided deposits, and other corners.

Empty AMM Pool

if (balances_.in == 0 || balances_.out == 0)
    return std::nullopt;  // No offer available

Iteration Limit Reached

if (ammContext.maxItersReached())
    return std::nullopt;  // Stop using AMM

Quality Worse Than CLOB

if (ammQuality < minAcceptableQuality)
    return std::nullopt;  // Skip AMM for this path

Debugging Tips

In brief: seeing AMM decisions in logs and RPC output.

Tracing AMM Offers

Enable detailed logging:

JLOG(j_.trace()) << "AMM offer: "
    << "in=" << amounts_.in
    << " out=" << amounts_.out
    << " quality=" << quality_;

Verifying Integration

Check that AMM is being considered:

# In rippled logs
grep "AMM offer" debug.log

Testing Quality Competition

Create test scenarios with known CLOB and AMM qualities to verify correct selection.

References to Source Code

Cross-References

  • AMM Architecture - Pool structure
  • AMM Logic - Quality and swap formulas
  • The complete transaction lifecycle module (Payment flow)

Summary

This module put the AMM to work through its seven transaction types (Create, Deposit, Withdraw, Vote, Bid, Delete, Clawback) and showed how pool liquidity reaches traders. Rather than being walled off, an AMM appears to pathfinding as synthetic offers, so a payment can route through pools and the order book together.

To remember:

  • Seven transactions: AMMCreate, AMMDeposit, AMMWithdraw, AMMVote, AMMBid, AMMDelete, AMMClawback
  • Deposit and withdraw come in proportional (both assets) and single-asset (with an implied swap) modes
  • AMMCreate builds the pool, the pseudo-account and the LP token, and costs a special (burned) fee
  • AMMBid spends LP tokens to win the auction slot's discounted trading fee
  • Pathfinding sees pools as synthetic offers: a payment can route through AMMs and the order book together
  • Inspect a live pool with the amm_info RPC
  • AMM-specific failures use the tecAMM_* family
  • Watch out: a single-asset deposit IS partly a swap; it moves the price and pays slippage even though you are "just adding liquidity"

Next up. You have seen what a big extension looks like. How does such a thing ever go live on a network nobody controls? Next: the amendment system.

Assignments

0 of 2 complete

Unlocks

Finishing this module opens up:

XRPL Academy © 2026