The seven AMM transaction types and how AMM liquidity is integrated into pathfinding alongside the order book.
What you'll learn
≈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.
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.
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
| 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%) |
Static validation before ledger access:
NotTEC AMMCreate::preflight(PreflightContext const& ctx)
{
// 1. Check Amount != Amount2 (different currencies)
if (ctx.tx[sfAmount] == ctx.tx[sfAmount2])
return temBAD_AMM_TOKENS;
// 2. Validate both amounts are positive
if (ctx.tx[sfAmount] <= beast::kZero ||
ctx.tx[sfAmount2] <= beast::kZero)
return temBAD_AMOUNT;
// 3. Check TradingFee range (0-1000)
if (ctx.tx[sfTradingFee] > TRADING_FEE_THRESHOLD)
return temBAD_FEE;
return tesSUCCESS;
}
Validation with ledger read access:
TER AMMCreate::preclaim(PreclaimContext const& ctx)
{
// 1. Check AMM doesn't already exist
if (ctx.view.read(keylet::amm(issue1, issue2)))
return tecDUPLICATE;
// 2. Validate account authorization for both assets
// 3. Check neither asset is frozen
// 4. Verify DefaultRipple is set on token issuers
// 5. Check sufficient XRP reserve for trustlines
// 6. Verify neither amount is an LP token
// 7. Check no clawback enabled (unless featureAMMClawback)
return tesSUCCESS;
}
Execution with ledger modifications:
TER AMMCreate::doApply()
{
// 1. Create pseudo-account for AMM
auto ammAccountID = calcAccountID(keylet::amm(...).key);
// 2. Calculate initial LP tokens
// LPT = sqrt(amount * amount2)
auto const lpTokens = ammLPTokens(amount, amount2, lptIssue);
// 3. Create ltAMM ledger entry
auto sleAMM = std::make_shared<SLE>(keylet::amm(...));
sleAMM->setFieldAmount(sfLPTokenBalance, lpTokens);
sleAMM->setFieldU16(sfTradingFee, tradingFee);
// ... set other fields
// 4. Transfer assets from creator to AMM account
// 5. Send LP tokens to creator
// 6. Initialize vote slots and auction slot
return tesSUCCESS;
}
Creating an AMM requires reserve for:
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
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) |
| 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 |
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;
}
// For tfLPToken flag (equal value from both assets)
TER AMMDeposit::doApply()
{
// 1. Get current pool state
auto const [asset1Balance, asset2Balance, lpBalance] = ammHolds(...);
// 2. Calculate required deposits for requested LP tokens
auto const ratio = lpTokensRequested / lpBalance;
auto const deposit1 = asset1Balance * ratio;
auto const deposit2 = asset2Balance * ratio;
// 3. Transfer assets to AMM
// 4. Mint LP tokens to depositor
// 5. Update ltAMM.LPTokenBalance
return tesSUCCESS;
}
// For tfSingleAsset flag (trading fee charged)
TER AMMDeposit::doApply()
{
// 1. Get pool state and trading fee
// 2. Calculate LP tokens using formula (with fee deduction)
auto const lpTokens = lpTokensOut(
assetBalance,
lpBalance,
depositAmount,
tradingFee
);
// 3. Transfer single asset to AMM
// 4. Mint calculated LP tokens
// 5. Update pool state
return tesSUCCESS;
}
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
| 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 |
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;
}
TER AMMWithdraw::doApply()
{
// 1. Calculate withdrawal amounts
auto const ratio = lpTokensIn / lpBalance;
auto const withdraw1 = asset1Balance * ratio;
auto const withdraw2 = asset2Balance * ratio;
// 2. Burn LP tokens
// 3. Transfer assets from AMM to withdrawer
// 4. Update ltAMM.LPTokenBalance
// 5. If LP balance becomes 0, mark for deletion
if (newLPBalance == 0)
// Pool can be deleted with AMMDelete
return tesSUCCESS;
}
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
| 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) |
TER AMMVote::doApply()
{
// 1. Get voter's LP token balance
auto const lpBalance = ammLPHolds(view, ammAccount, voterAccount);
// 2. Calculate vote weight
auto const weight = (lpBalance / totalLPTokens) * VOTE_WEIGHT_SCALE_FACTOR;
// 3. Find or create vote slot
if (existingSlot)
{
// Update existing vote
slot.FeeVal = proposedFee;
slot.VoteWeight = weight;
}
else if (voteSlots.size() < VOTE_MAX_SLOTS)
{
// Add new vote slot
voteSlots.push_back({account, proposedFee, weight});
}
else
{
// Replace lowest weight vote if ours is higher
auto minSlot = findMinWeightSlot(voteSlots);
if (weight > minSlot.VoteWeight)
*minSlot = {account, proposedFee, weight};
else
return tecAMM_FAILED;
}
// 4. Recalculate trading fee as weighted average
uint32_t newFee = calculateWeightedFee(voteSlots);
sleAMM->setFieldU16(sfTradingFee, newFee);
return tesSUCCESS;
}
constexpr std::uint16_t VOTE_MAX_SLOTS = 8;
constexpr std::uint32_t VOTE_WEIGHT_SCALE_FACTOR = 100000;
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
| 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 |
TER AMMBid::doApply()
{
// 1. Calculate required bid based on slot state
auto const minBid = calculateMinBid(
currentSlot,
timeRemaining,
minSlotPrice
);
// 2. Determine actual bid (between BidMin and BidMax)
auto const actualBid = std::clamp(minBid, bidMin, bidMax);
// 3. Calculate refund to previous holder
auto const refund = (1 - timeFractionUsed) * currentSlot.Price;
// 4. Execute bid
// - Transfer LP tokens from bidder
// - Refund to previous holder
// - Burn remaining (actualBid - refund)
// 5. Update auction slot
auctionSlot.Account = bidder;
auctionSlot.Expiration = now + 24h;
auctionSlot.DiscountedFee = 0; // Usually 0 for slot holder
auctionSlot.Price = actualBid;
auctionSlot.AuthAccounts = authAccounts;
return tesSUCCESS;
}
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;
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
| Field | Required | Description |
|---|---|---|
| Asset | Yes | First asset issue (identifies pool) |
| Asset2 | Yes | Second asset issue (identifies pool) |
TER AMMDelete::preclaim(PreclaimContext const& ctx)
{
// 1. Verify AMM exists
// 2. Check LP token balance is 0
if (sleAMM->getFieldAmount(sfLPTokenBalance) != beast::kZero)
return tecAMM_NOT_EMPTY;
return tesSUCCESS;
}
TER AMMDelete::doApply()
{
// 1. Delete trustlines (limited per transaction)
auto const maxTrustlines = ctx.view().rules().enabled(fixAMMv1_3)
? AMM_MAX_TRUSTLINES_DELETE_V3
: AMM_MAX_TRUSTLINES_DELETE;
auto deleted = deleteAMMTrustlines(view, ammAccount, maxTrustlines);
// 2. If trustlines remain, return incomplete
if (remainingTrustlines > 0)
return tecINCOMPLETE;
// 3. Delete ltAMM ledger entry
view.erase(sleAMM);
// 4. Delete pseudo-account
view.erase(sleAMMAccount);
return tesSUCCESS;
}
For pools with many trustlines (from LP token holders), deletion happens incrementally:
tecINCOMPLETE if more remainIn 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
featureAMMClawback amendment must be enabledlsfAllowTrustLineClawback flag set| 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) |
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;
}
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 |
src/libxrpl/tx/transactors/dex/AMMCreate.cppsrc/libxrpl/tx/transactors/dex/AMMDeposit.cppsrc/libxrpl/tx/transactors/dex/AMMWithdraw.cppsrc/libxrpl/tx/transactors/dex/AMMVote.cppsrc/libxrpl/tx/transactors/dex/AMMBid.cppsrc/libxrpl/tx/transactors/dex/AMMDelete.cppsrc/libxrpl/tx/transactors/dex/AMMClawback.cppinclude/xrpl/protocol/detail/transactions.macroIn 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.
In brief: the components between a payment and the pool.
| 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 |
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
class AMMContext {
AccountID account_; // Transaction sender
bool multiPath_; // Using multiple paths?
bool ammUsed_; // AMM consumed this iteration?
std::uint16_t ammIters_; // AMM iteration counter
constexpr static std::uint8_t MaxIterations = 30;
public:
// Mark AMM offer as consumed
void setAMMUsed() { ammUsed_ = true; }
// Called after each iteration
void update() {
if (ammUsed_)
++ammIters_;
ammUsed_ = false; // Reset for next iteration
}
// Check iteration limit
bool maxItersReached() const {
return ammIters_ >= MaxIterations;
}
// Reset for new iteration
void clear() { ammUsed_ = false; }
};
The 30-iteration limit prevents:
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
template <typename TIn, typename TOut>
class AMMLiquidity {
AccountID ammAccountID_;
std::uint32_t tradingFee_;
Issue issueIn_;
Issue issueOut_;
TAmounts<TIn, TOut> initialBalances_;
public:
// Get AMM offer for payment path
std::optional<AMMOffer<TIn, TOut>>
getOffer(ReadView const& view, AMMContext& ctx) const;
// Fetch current pool balances
TAmounts<TIn, TOut>
fetchBalances(ReadView const& view) const;
// Generate offer matching CLOB quality
std::optional<TAmounts<TIn, TOut>>
generateOfferForQuality(Quality const& quality) const;
// Fibonacci sequence for multi-path
std::optional<TAmounts<TIn, TOut>>
generateFibSeqOffer(std::uint16_t iteration) const;
};
When processing a single payment path, AMM offers are sized to match CLOB quality:
std::optional<AMMOffer<TIn, TOut>>
AMMLiquidity::getOffer(ReadView const& view, AMMContext& ctx) const
{
// Get best CLOB offer quality
auto const clobQuality = getBestCLOBQuality(view);
// Generate AMM offer matching this quality
auto const amounts = changeSpotPriceQuality(
balances_,
clobQuality,
tradingFee_
);
if (!amounts)
return std::nullopt;
return AMMOffer<TIn, TOut>(*this, *amounts, balances_, quality);
}
For payments using multiple paths, Fibonacci sequence sizing prevents over-concentration:
std::optional<TAmounts<TIn, TOut>>
AMMLiquidity::generateFibSeqOffer(std::uint16_t iteration) const
{
// Fibonacci fractions: 5/20000, 8/20000, 13/20000, 21/20000, ...
static constexpr std::array<std::uint16_t, 10> fib = {
5, 8, 13, 21, 34, 55, 89, 144, 233, 377
};
auto const fraction = Number(fib[iteration]) / 20000;
auto const offerIn = balances_.in * fraction;
auto const offerOut = swapAssetIn(balances_, offerIn, tradingFee_);
return TAmounts{offerIn, offerOut};
}
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
AMMOffers are not ledger objects - they are synthetic, ephemeral offers generated on-the-fly:
| 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() |
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
template <typename TIn, typename TOut>
class AMMOffer {
AMMLiquidity<TIn, TOut> const& ammLiquidity_;
TAmounts<TIn, TOut> amounts_; // Offer amounts
TAmounts<TIn, TOut> balances_; // Current pool balances
Quality quality_; // Spot price quality
bool consumed_; // Has been consumed?
public:
// Get offer quality (exchange rate)
Quality quality() const { return quality_; }
// Limit output to specific amount
void limitOut(TOut const& limit);
// Limit input to specific amount
void limitIn(TIn const& limit);
// Apply offer to AMM pool
void consume();
// Verify pool invariant after trade
bool checkInvariant() const;
};
Quality AMMOffer::quality() const
{
// Quality = out / in (how much you get per unit spent)
return Quality(amounts_.out / amounts_.in);
}
When the payment doesn't need the full offer:
void AMMOffer::limitOut(TOut const& limit)
{
if (limit < amounts_.out)
{
// Recalculate input for limited output
amounts_.in = swapAssetOut(balances_, limit, tradingFee_);
amounts_.out = limit;
}
}
void AMMOffer::limitIn(TIn const& limit)
{
if (limit < amounts_.in)
{
// Recalculate output for limited input
amounts_.out = swapAssetIn(balances_, limit, tradingFee_);
amounts_.in = limit;
}
}
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());
}
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
std::pair<TAmounts, bool>
BookStep::compute(
PaymentSandbox& view,
AMMContext& ammContext,
...)
{
// 1. Get CLOB offers
auto clobOffers = getOrderBookOffers(view);
// 2. Get AMM offer (if available)
auto ammOffer = ammLiquidity_.getOffer(view, ammContext);
// 3. Interleave based on quality
while (hasOffers())
{
// Compare qualities
auto const clobQuality = clobOffers.front().quality();
auto const ammQuality = ammOffer ? ammOffer->quality() : Quality{0};
if (ammQuality >= clobQuality && ammOffer)
{
// Use AMM offer (better or equal quality)
consumeAMMOffer(*ammOffer, ammContext);
// Generate new AMM offer for remaining
ammOffer = ammLiquidity_.getOffer(view, ammContext);
}
else
{
// Use CLOB offer
consumeCLOBOffer(clobOffers.front());
clobOffers.pop_front();
}
}
return {totalConsumed, success};
}
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.
In brief: one payment split across book and pool.
Payment: 10,000 XRP -> USD Available liquidity:
Iteration 1:
- CLOB offer: 5,000 XRP @ 2.00
- AMM offer: Generated to match 2.00 quality
- Result: Split between both at equal quality
Iteration 2:
- CLOB offer: 3,000 XRP @ 1.98
- AMM offer: New quality after iteration 1
- Result: CLOB wins (better quality)
Iteration 3:
- Remaining: ~2,000 XRP
- AMM fills remainder at current pool quality
Total: 10,000 XRP -> ~19,800 USD
(Blend of CLOB and AMM liquidity)
In brief: what all this costs per payment.
// Maximum AMM iterations per payment
constexpr std::uint8_t MaxIterations = 30;
Why 30?
// Cache quality calculations to avoid recomputation
Quality cachedQuality_;
bool qualityValid_ = false;
Quality getQuality() {
if (!qualityValid_) {
cachedQuality_ = computeQuality();
qualityValid_ = true;
}
return cachedQuality_;
}
// Snapshot balances at start to avoid repeated ledger reads
TAmounts<TIn, TOut> initialBalances_;
AMMLiquidity(...) {
initialBalances_ = fetchBalances(view);
}
In brief: empty pools, one-sided deposits, and other corners.
if (balances_.in == 0 || balances_.out == 0)
return std::nullopt; // No offer available
if (ammContext.maxItersReached())
return std::nullopt; // Stop using AMM
if (ammQuality < minAcceptableQuality)
return std::nullopt; // Skip AMM for this path
In brief: seeing AMM decisions in logs and RPC output.
Enable detailed logging:
JLOG(j_.trace()) << "AMM offer: "
<< "in=" << amounts_.in
<< " out=" << amounts_.out
<< " quality=" << quality_;
Check that AMM is being considered:
# In rippled logs
grep "AMM offer" debug.log
Create test scenarios with known CLOB and AMM qualities to verify correct selection.
src/libxrpl/tx/paths/AMMLiquidity.cpp - Offer generationsrc/libxrpl/tx/paths/AMMOffer.cpp - Offer representationinclude/xrpl/tx/transactors/dex/AMMContext.h - State managementsrc/libxrpl/tx/paths/BookStep.cpp - Integration pointinclude/xrpl/ledger/helpers/AMMHelpers.h - Quality calculationsThis 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:
amm_info RPCtecAMM_* familyNext 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.
Resources
Assignments
0 of 2 complete