AIMM Overview

BTR pools implement an AIMM: a multi-asset AMM quoting off a keeper-pushed external mark instead of a bonding curve, with mid and spread adapting to per-asset inventory and realized volatility. This page is the map: each mechanism gets one line and a link to the page that states it in full. Rosters per chain: Deployments.


1. Core components

ComponentWhat it isFull statement
Single-sided depositsLP deposits one token, receives fungible LP tokensProviding Liquidity
N-asset poolingAnchor-tree topology, any-to-any pricing along the unique tree path; rosters grouped by correlated asset class so inventory nets across legsPool Composition
Inventory-based pricingAvellaneda-Stoikov mid shift off coverageInventory Management
Coverage-aware ALMReserves / liabilities separation (Wombat-style)§7
Clamped quartic I-spline depth curvesC2 density, monotone (nondecreasing control weights); five presets in a shared per-pool table, assets point in via presetId§8, Liquidity Shaping
External-mark feedKeeper pushes a fresh per-asset mark (θ + heartbeat); Pool quotes off it, no on-chain price EMA§6, Feed Oracle
Singleton contracts + ERC-1967 beacon proxiesEvery pool reads PoolFactory.implementation(); Admin and Flash are standalone singletons shared across pools§2.1
Optional per-asset hooks (dual ledger)Physical rehypothecation of idle liquidity, R=Rliq+Rinv; pricing and coverage use full R, a liquid buffer keeps typical swaps at 0 hook CALL. Example: CompoundV2YieldHook against VenusPool Hooks

Call recipes (swap / LP / deploy / oracles) live in Developer Guides; this section stays conceptual.


2. Contract Architecture

2.1. Standalone Singletons + Pool Proxies

external call

external call

deploys

reads impl

owner ref

owner ref

User

Pool beacon proxy

Admin

Flash

PoolFactory

AccessControl

  • Pool is the whole pool-side entry surface and answers every call directly. It DELEGATECALLs external library functions (Pricing, PoolConfig, PoolLiquidity, NUQuartic) through normal Solidity linking; those four targets are fixed at compile time, an EIP-170 code-size measure rather than a runtime module registry.
  • Each contract uses its own default storage layout. Each Pool holds its own PoolStorage at slot 0, set once via initialize. Storage is per-instance, code is not: the implementation is replaceable via a GOVERNANCE-tier timelocked swap at PoolFactory (7 days in production) that re-points every live pool at once while their storage persists. Largest trust assumption in the protocol: Admin.
  • Singletons (Admin, Flash) are key-by-(pool, …), so one deployment serves every pool. Both are UUPS implementations behind ERC-1967 proxies; Pool bakes each proxy address as an immutable and PoolFactory._validateImplementation pins them on every fleet upgrade.
  • Owner authority for every singleton routes through one shared AccessControl singleton.

2.2. Core Contracts

ContractFilePurpose
PoolPool.solSwap, deposit, withdraw, donate, liability swap. Reads the external-mark feed (ExternalOracle).
AdminAdmin.solPer-pool timelocked configuration. UUPS behind an ERC-1967 proxy.
FlashFlash.solERC-3156-style (postFlashLoan variant) flash loans. UUPS behind an ERC-1967 proxy.
PoolFactoryPoolFactory.solDeploys ERC-1967 beacon proxies. It is the beacon: it holds the fleet implementation slot and the impl-swap timelock.
AccessControlAccessControl.solSingle owner ref consumed by all singletons.
ExternalOracleExternalOracleV5.sol (behind OracleBeacon)k-of-n signed keeper mark feed; the quote source every pool reads.
LPTokenLPToken.solPer-leg ERC-20 share receipt, one EIP-1167 clone per (pool, leg), minted and burned by the owning pool only.

3. Core Data Structures

Struct definitions: IPool.sol. Full field reference: Parametrization.

Key per-asset fields:

  • Reserves and liabilities, for coverage tracking
  • Anchor pointer (parent in the anchor tree)
  • vegaBps, this leg’s σ-sensitivity slope (BPS = 1x), and minDispersionPbps, the quiet-tape band floor. σ scales the band up from that floor; the ceiling is structural, derived from the leg’s preset curve (Pricing.dispersionCap) off the interior swing cap and bound at the write path. Inventory skew is a fixed protocol law with no per-asset dial
  • minFeePbps, bounded two-sidedly at MIN_FEE_PBPS (1) and ONE_PCT_PBPS (1%) at every write. It floors the spread, not the fee (§11.3), and it is the only fee rate the asset carries
  • presetId, the pointer into the pool’s shared curve table (0 refused at config)
  • depositCapCode, the leg’s notional cap in whole base tokens (m·10^e), and maxLiabWeightBps, a soft cap on the leg’s share of the pool claim book (0 = off). Both bind at credit time only

4. Pricing System

4.1. Pipeline

swap request

Calculate Coverage

Compute Inventory Skew

Get Oracle Price

Calculate Volatility

Traverse Preset Curve

Apply Spread and Fees

amountOut

4.2. Key Concepts

TermDefinitionOwner page
Coverage ratioc=R/LInventory Management
Inventory skewA-S mid shift, piecewise-linear in c and saturating at ±100: +200(1-c) draining, -100(c-1) filling. The arms are asymmetric on purpose (the filling slope is the round-trip impact-conservation bound); no per-asset dialInventory Management
SpreadSymmetric round-trip fee width: volatility band + confidence + keeper-staleness surcharges, no directional surcharge. A swap pays half of it, once, on the outputSpread & Fees
Curve traversalPrice impact via O(1) quartic I-spline integration. Direction-asymmetric, unlike the spread, because depth is per-asset and the traverse starts at an off-center skew anchorLiquidity Shaping

Canonical vocabulary (mark, mid, skew, impact, spread, fee, toll) and the term-by-term cost decomposition: Slippage & Price Impact §1.1.


5. Anchor Tree Paths

5.1. Topology

WBTC base

WETH

USDC

stETH

USDT

DAI

Every asset anchors to one parent and every chain terminates at the base token, the root. The parent need not be the base: the contracts ship the general anchor tree, so any asset may anchor to a non-base parent up to MAX_DEPTH = 4 and a curator can give a correlated pair its own edge, feed, σ and fee floor instead of forcing it through the base mark. A pool’s actual shape is the anchor column of its risk-param file; an empty column anchors every leg to the base. Activating a deep edge needs the cross pair’s mark on NX Rates, a configuration and data step rather than a contract change. See Anchor Path Pricing §1.1.

5.2. Swap Path (unique, via the LCA)

The path between two assets is the unique tree path: up to the lowest common ancestor, then down.

stETH

WETH

WBTC

USDC

USDT

[stETH, WETH, WBTC, USDC, USDT] is 4 legs: stETH→WETH, WETH→WBTC, WBTC→USDC, USDC→USDT. A pair sharing a low ancestor stays short: USDT → USDC → DAI is 2 legs and never touches the WBTC mark.

Constraints:

  • MAX_DEPTH = 4 bounds one walk; a path is two walks meeting at the LCA, so MAX_PATH_LENGTH = 2 * MAX_DEPTH + 1 = 9 nodes and 8 legs
  • Endpoint legs: full impact, reserves settle. Interior legs: mid with skew, no impact, no settlement
  • Path is unique, so there is nothing to search and no decomposition ambiguity
  • Cycles rejected by validateAnchor (explicit self-check plus an unconditional step cap)

This intra-pool path resolves inside a single Pool.swap call, with no router involved; aggregators call Pool.swap directly. Cross-pool routing (best pool for a pair, splitting a large trade to minimize price impact) is selected off-chain by the frontend router POST /v1/route, then settled leg by leg through @btr-protocol/sdk buildSwapCalls (EIP-5792 or sequential) or handed whole to the Router singleton for one all-or-nothing transaction. See Quotes & Routing, Composability §2 and Anchor Path Pricing.


6. Oracle System

6.1. External-Mark Feed

Price discovery is external: no internal TWAP, no write-on-swap. NX Rates signs a fresh per-asset mark with sigmaPbps (realized vol) and confidenceBps (a 1σ band); any keeper lands the batch via ExternalOracleV5.push (k-of-n) once the price moves past a deviation band θ or a heartbeat elapses. Every quote (mid, spread, depeg band) reads that mark and nothing is smoothed or averaged on-chain. Quoting off a fresh mark rather than a lagging average removes classical curve LVR, but not push-latency LVR or OEV (Oracle Keeper).

Feed contract, encodings and failure modes: Oracle Keeper. Pool-side read path: Feed Oracle.

6.2. Gas Optimization

Oracle reads are cached in transient storage (EIP-1153), so a repeat read inside one transaction is a TLOAD rather than an external call (§12).


7. Coverage-Aware ALM

ALM tracks reserves against LP claims per asset. Formulas and edges: Inventory Management.

  • Coverage ratio c=R/L (100% = equilibrium)
  • Pool rate C=R·m/L·m over the roster; every LP mint and exit settles at it
  • Undercollateralized (c < 100%): positive skew, and a same-asset exit is capped in kind at c
  • Overcollateralized (c > 100%): skew discounts; surplus raises C and is LP-redeemable through it

Two safety mechanisms, neither on a clock, neither reducing liabilities on its own:

  • One LP settlement rate: exits price off C, which no exit moves by exiting, so there is no first-mover advantage
  • Convex coverage toll (kappaCovBps): any swap draining a walled leg further pays a cost rising superlinearly as c falls

8. Liquidity Curves

Clamped quartic I-spline preset curves define liquidity distribution across the depth axis. Preset design and selection: Liquidity Shaping.

  • C2 density, monotone (nondecreasing control weights; 1-14 segments)
  • Exact O(1) range integration via stored prefix integrals; cost flat in trade size
  • Five-preset codebook in a shared per-pool table. The reference roster assigns all five across 28 legs; the live fleet ships four (preset 3 unused) across 26 symbols, all on interior knots [1314, 8686] (m = 3 spans). They carry three distinct wQ control polygons, whose half-swing at the reference dispersion is 100, 200 and 500 pbps (1, 2 and 5 bp). Live quotes y-scale by dispersion / dispRefPbps
  • The three wQ vectors are independent fits, not rescalings, off exact multiples of each other by 1-2 ULP. The shipped vectors are canonical on-chain state, so a rescaled regeneration fails parity: never synthesize one preset from another, re-fit (Liquidity Shaping §4.3)
  • The table is a quantized density codebook: an asset’s observed depth density is fitted off-chain and presetId points at the nearest entry, while the continuous dispersion / dispRefPbps scale absorbs the scale part of the residual, so the codebook only has to span shape (Liquidity Shaping §2.2)
  • The traverse is anchored on each curve’s density median, stored in the header, so zero inventory skew quotes the mark for any shape

9. Storage Layout

9.1. Per-Contract Layouts

Each singleton uses default Solidity storage (no ERC-7201 namespacing). Cross-pool keying is mapping(address pool => ...) at the storage root.

ContractLayoutPurpose
Pool (beacon proxy)PoolStorage at slot 0Per-pool assets, reserves, config, set once via initialize. Append-only field order, because live pools keep this storage across an implementation swap.
AdminpendingOps[keccak256(pool, opId, subject)], pendingData[...]Per-pool timelock queue, keyed by op and subject (Admin §3).
Flashnone (reads pool state)Stateless.

9.2. Transient Storage (EIP-1153)

Reentrancy guards, oracle price caching (§6.2), flash loan state.


10. Admin timelocks

10.1. Operation Types

Every governed operation is gated by one of the GOVERNANCE (7 d) / LISTING (1 d) / TUNING (1 h) timelock tiers. Full duration table with on-chain constant names: Access Control.

10.2. Two-Phase Execution

  1. admin.requestOp(pool, opType, subject, payload) → stores pending, emits TimelockRequested(pool, id, opType, executableAt)
  2. Wait for the tier delay (the deployment’s GOV_DELAYS schedule)
  3. admin.execute<Op>(pool, ...) → applies within the grace period, emits the operation’s own event

The request side is one generic entry point: every operation type queues through Admin.requestOp with an opType discriminator, and one cancelTimelock serves them all (owner or any guardian). Only the execute side is per-op named (executeAddAsset, executeSetCurve, executeAnchorUpdate), because each applies its own typed payload. See Admin §4.


11. Key Invariants

Properties for fuzzing and formal verification: Invariants.

11.1. Coverage Bounds

c[0,)

  • c = 1.0 → equilibrium
  • c < 1.0 → undercollateralized (positive skew; same-asset exits capped in kind)
  • c > 1.0 → overcollateralized

11.2. Skew Bounds

-100ψ+100

The skew index ψ displaces the spline coordinate off the curve’s stored density median x*, not off the domain midpoint: x0=clamp(x*+ψ·BPS/200,0,BPS). Anchoring on the stored median is what makes zero skew quote the mark for any shape; the BPS/200 slope is bound there by round-trip impact conservation on both arms. Derivation: Liquidity Shaping §5.1.

11.3. Spread Bounds

Simax(fmin,i,Fi)

S is bounded below by the summed per-leg floors and above only by its uint16 field width: a spread widened by a σ, confidence or staleness term is the price of that risk, and a per-leg ceiling would break path additivity. Trader protection is minAmountOut. minFeePbps floors the path spread S per leg, not the fee: a round trip pays S, a single swap pays S/2 charged once on the output. Full statement: Spread & Fees §3 and §5.

11.4. Anchor Tree

  • MAX_DEPTH = 4: every anchor chain reaches the base within 4 steps
  • MAX_PATH_LENGTH = 9: 2*MAX_DEPTH + 1 nodes (8 legs: up to the LCA, then down)
  • noCycles = true: explicit self-check + unconditional step cap

12. Gas Optimizations

OptimizationSavings
Single-slot FeedData packing~2,100 gas/read
Transient oracle caching~2,100 gas/hit
Packed timelocks66% slot reduction
Anchor-tree path walk (depth ≤ 4, ≤ 8 legs, no storage)Storage-free path resolution
Bitmask hooks32 bits vs N mappings
Packed quartic curve (header directory + prefix integrals)Eval 5.4k / O(1) range integral 11.2k cold

Per-operation swap figures: Pool §12.


13. Error Handling

Minimal consolidated error set, Errors.sol (Err library):

ErrorUsage
ZeroValue()Zero address/amount/price
InsufficientAmount(available, required)Balance checks
ExcessiveAmount(amount, limit)Limit exceeded
InvalidState()Not initialized/paused
FeatureDisabled(resource)Swap/flash disabled
NotConfigured(resource, target)Missing config
ThresholdViolation(value, threshold)Slippage/coverage
StaleData(age, maxAge)Oracle staleness
Reentrancy()Guard triggered (Solady ReentrancyGuardTransient)

14. Contract Deployment

14.1. Immutable Components

  • All AIMM libraries. Four are DEPLOYED and linked (Pricing, PoolConfig, PoolLiquidity, NUQuartic); the *Lib ones (FeedMathLib, AnchorTreeLib, PoolIOLib, PoolHooksLib, TransientCacheLib, PoolConstantsLib) are internal and inline into their callers.
  • AccessControl (shared singleton, non-upgradeable: Ownable, no proxy)

14.2. Replaceable via Factory Timelock

Pool implementation, swappable via a 7-day timelock at PoolFactory. The swap re-points every live pool, third-party pools included; there is no opt-out. Cancellable by owner or guardian, expires 7 days after maturity (Admin).

14.3. Upgradeable via UUPS

Admin and Flash, each a UUPS implementation behind its own ERC-1967 proxy, gated by UpgradeGate at the GOVERNANCE tier (7 days in production). Admin holds per-pool state (bootstrapSealed, riskFences, pendingOps), so a redeploy-and-repoint is not equivalent to an upgrade.


PageCovers
Inventory ManagementCoverage, skew, pool rate
Liquidity ShapingPreset depth curves
Anchor Path PricingPath composition, refFeedId
Spread & Feesσ, confidence, staleness, the fee
Slippage & Price ImpactExecution costs, minAmountOut, deadline
Toxic Flow MitigationFlow guards
ParametrizationParameter reference
InvariantsFuzzing and formal-verification properties
Pool · Feed Oracle · Admin · FlashModule references
Pool HooksDual ledger, buffer, CompoundV2YieldHook