This describes a pre-release version of LBAMM. Interfaces and behavior may change.
Verify the exact repository commit before building production integrations.
Pool Abstraction
LBAMM supports heterogeneous pool types under a unified execution and enforcement framework.
At a high level:
- AMM Core owns token custody, hook execution, and invariant enforcement.
- Pool Types provide pricing logic, position logic, and pool-specific state.
- Pools are identified by a deterministic
poolIdthat encodes key parameters.
This page defines the contract boundary between core and pool types.
What a Pool Is
A pool in LBAMM consists of:
token0andtoken1(canonical ordering enforced at creation)- A
poolTypecontract (execution logic module) - A pool fee (fixed BPS or dynamic sentinel)
- An optional
poolHook - Deterministic
poolId
Multiple pools may share the same token pair. They are distinguished by:
poolTypefeepoolHookpoolParams(pool-type-specific initialization data)
Core vs Pool Type Responsibilities
Core Responsibilities
Core:
- Custodies reserves
- Tracks LP fee balances
- Tracks protocol fees
- Executes token, position, and pool hooks
- Performs all token transfers
- Enforces invariants on returned values
Core is invariant-aware.
Pool Type Responsibilities
Pool types:
- Implement pricing and liquidity logic
- Maintain pool-specific state
- Compute swap outcomes
- Compute LP and protocol fee amounts
- Return deterministic outputs to core
Pool types:
- Do not transfer tokens
- Do not custody reserves
- Do not mutate core accounting
They return values. Core settles.
Core Pool State
Core stores a minimal, pool-agnostic structure:
struct PoolState {
address token0;
address token1;
address poolHook;
uint128 reserve0;
uint128 reserve1;
uint128 feeBalance0;
uint128 feeBalance1;
}
Meaning:
reserve0/reserve1are canonical reserves.feeBalance0/feeBalance1represent unclaimed LP fees only.- Protocol fees are stored separately.
poolHookis immutable after creation.
Pool types may maintain additional internal state keyed by poolId.
poolId Encoding
poolId is deterministic and bit-packed.
/// poolId is a packed value of the pool type address,
/// hash of creation details, and pool-specific packed data.
///
/// Bits 0 to 15 - pool fee in BPS.
/// Bits 16 to 143 - creation details hash (may include pool-specific params).
/// Bits 144 to 255 - pool type address (must have 6 leading zero bytes).
Constraints:
- Pool type addresses must have 6 leading zero bytes.
- Encoded pool type must match
details.poolType. - Encoded fee must match
details.fee.
Core validates both during creation.
PoolDecoder Utilities
Core extracts encoded components using PoolDecoder:
library PoolDecoder {
function getPoolType(bytes32 poolId) internal pure returns (address poolType) {
assembly ("memory-safe") {
poolType := shr(POOL_ID_TYPE_ADDRESS_SHIFT, poolId)
}
}
function getPoolFee(bytes32 poolId) internal pure returns (uint16 fee) {
fee = uint16(uint256(poolId) >> POOL_ID_FEE_SHIFT);
}
}
poolId is the canonical routing and indexing key.
Pool Creation
Creation parameters:
struct PoolCreationDetails {
address poolType;
uint16 fee;
address token0;
address token1;
address poolHook;
bytes poolParams;
}
Creation flow:
- Validate token contracts.
- Enforce canonical ordering (
token0 < token1). - Validate fee:
- ≤ 10,000 BPS
- or dynamic sentinel
- Delegate to pool type:
poolId = poolType.createPool(details); - Validate returned
poolIdencoding. - Store
PoolState. - Execute token and pool creation hooks.
- Emit
PoolCreated.
Event:
event PoolCreated(
address indexed poolType,
address indexed token0,
address indexed token1,
bytes32 poolId,
address poolHook
);
Dynamic Fee Sentinel
Dynamic fee pools use:
uint16 constant DYNAMIC_POOL_FEE_BPS = 55_555;
If this sentinel is used:
- A non-zero
poolHookmust be provided. - The pool hook participates in dynamic fee calculation.
Pool Type Interface
All pool types must implement ILimitBreakAMMPoolType.
Swap Boundary Guarantees
For swaps:
- Pool type returns computed amounts.
- Core validates LP fee and protocol fee correctness.
- Core updates reserves.
- Core performs token transfers.
- Pool types never move tokens directly.
Multi-hop swaps are decomposed by core into sequential swapByInput or swapByOutput calls per hop.
Read Surfaces
getCurrentPriceX96
function getCurrentPriceX96(address amm, bytes32 poolId)
external
view
returns (uint160 sqrtPriceX96);
Provides a standardized price read surface across heterogeneous pool types.
poolTypeManifestUri
function poolTypeManifestUri()
external
view
returns (string memory manifestUri);
Provides integration metadata for applications and SDKs.
If updated, pool types must emit:
event PoolTypeManifestUriUpdated(string uri);
Determinism Model
Pool types may:
- Use oracle accumulators
- Use volatility metrics
- Use time-dependent state
As long as:
- Outputs are deterministic given onchain state and inputs
- Returned values are consistent with encoded fee rates
- Invariants on reserves and fees are respected
Core enforces accounting correctness.
Summary
LBAMM separates:
- Execution & custody (core)
- Pricing & liquidity logic (pool types)
poolId encodes:
- Pool type
- Fee
- Creation parameters
This architecture enables heterogeneous liquidity models to coexist safely under unified invariant enforcement.
