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
| Component | What it is | Full statement |
|---|---|---|
| Single-sided deposits | LP deposits one token, receives fungible LP tokens | Providing Liquidity |
| N-asset pooling | Anchor-tree topology, any-to-any pricing along the unique tree path; rosters grouped by correlated asset class so inventory nets across legs | Pool Composition |
| Inventory-based pricing | Avellaneda-Stoikov mid shift off coverage | Inventory Management |
| Coverage-aware ALM | Reserves / liabilities separation (Wombat-style) | §7 |
| Clamped quartic I-spline depth curves | C2 density, monotone (nondecreasing control weights); five presets in a shared per-pool table, assets point in via presetId | §8, Liquidity Shaping |
| External-mark feed | Keeper pushes a fresh per-asset mark (θ + heartbeat); Pool quotes off it, no on-chain price EMA | §6, Feed Oracle |
| Singleton contracts + ERC-1967 beacon proxies | Every 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, ; pricing and coverage use full , a liquid buffer keeps typical swaps at 0 hook CALL. Example: CompoundV2YieldHook against Venus | Pool Hooks |
Call recipes (swap / LP / deploy / oracles) live in Developer Guides; this section stays conceptual.
2. Contract Architecture
2.1. Standalone Singletons + Pool Proxies
Poolis the whole pool-side entry surface and answers every call directly. It DELEGATECALLsexternallibrary 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
Poolholds its ownPoolStorageat slot 0, set once viainitialize. Storage is per-instance, code is not: the implementation is replaceable via aGOVERNANCE-tier timelocked swap atPoolFactory(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;Poolbakes each proxy address as an immutable andPoolFactory._validateImplementationpins them on every fleet upgrade. - Owner authority for every singleton routes through one shared
AccessControlsingleton.
2.2. Core Contracts
| Contract | File | Purpose |
|---|---|---|
| Pool | Pool.sol | Swap, deposit, withdraw, donate, liability swap. Reads the external-mark feed (ExternalOracle). |
| Admin | Admin.sol | Per-pool timelocked configuration. UUPS behind an ERC-1967 proxy. |
| Flash | Flash.sol | ERC-3156-style (postFlashLoan variant) flash loans. UUPS behind an ERC-1967 proxy. |
| PoolFactory | PoolFactory.sol | Deploys ERC-1967 beacon proxies. It is the beacon: it holds the fleet implementation slot and the impl-swap timelock. |
| AccessControl | AccessControl.sol | Single owner ref consumed by all singletons. |
| ExternalOracle | ExternalOracleV5.sol (behind OracleBeacon) | k-of-n signed keeper mark feed; the quote source every pool reads. |
| LPToken | LPToken.sol | Per-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), andminDispersionPbps, 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 dialminFeePbps, bounded two-sidedly atMIN_FEE_PBPS(1) andONE_PCT_PBPS(1%) at every write. It floors the spread, not the fee (§11.3), and it is the only fee rate the asset carriespresetId, 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), andmaxLiabWeightBps, 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
4.2. Key Concepts
| Term | Definition | Owner page |
|---|---|---|
| Coverage ratio | Inventory Management | |
| Inventory skew | A-S mid shift, piecewise-linear in and saturating at : draining, filling. The arms are asymmetric on purpose (the filling slope is the round-trip impact-conservation bound); no per-asset dial | Inventory Management |
| Spread | Symmetric round-trip fee width: volatility band + confidence + keeper-staleness surcharges, no directional surcharge. A swap pays half of it, once, on the output | Spread & Fees |
| Curve traversal | Price 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 anchor | Liquidity 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
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] 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 = 4bounds one walk; a path is two walks meeting at the LCA, soMAX_PATH_LENGTH = 2 * MAX_DEPTH + 1 = 9nodes 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 (100% = equilibrium)
- Pool rate 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 atc - Overcollateralized (
c > 100%): skew discounts; surplus raisesCand 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 ascfalls
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 distinctwQcontrol polygons, whose half-swing at the reference dispersion is 100, 200 and 500 pbps (1, 2 and 5 bp). Live quotes y-scale bydispersion / dispRefPbps - The three
wQvectors 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
presetIdpoints at the nearest entry, while the continuousdispersion / dispRefPbpsscale 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.
| Contract | Layout | Purpose |
|---|---|---|
Pool (beacon proxy) | PoolStorage at slot 0 | Per-pool assets, reserves, config, set once via initialize. Append-only field order, because live pools keep this storage across an implementation swap. |
Admin | pendingOps[keccak256(pool, opId, subject)], pendingData[...] | Per-pool timelock queue, keyed by op and subject (Admin §3). |
Flash | none (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
admin.requestOp(pool, opType, subject, payload)→ stores pending, emitsTimelockRequested(pool, id, opType, executableAt)- Wait for the tier delay (the deployment’s
GOV_DELAYSschedule) 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 = 1.0→ equilibriumc < 1.0→ undercollateralized (positive skew; same-asset exits capped in kind)c > 1.0→ overcollateralized
11.2. Skew Bounds
The skew index displaces the spline coordinate off the curve’s stored density median , not off the domain midpoint: . Anchoring on the stored median is what makes zero skew quote the mark for any shape; the slope is bound there by round-trip impact conservation on both arms. Derivation: Liquidity Shaping §5.1.
11.3. Spread Bounds
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 per leg, not the fee: a round trip pays , a single swap pays 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 stepsMAX_PATH_LENGTH = 9:2*MAX_DEPTH + 1nodes (8 legs: up to the LCA, then down)noCycles = true: explicit self-check + unconditional step cap
12. Gas Optimizations
| Optimization | Savings |
|---|---|
| Single-slot FeedData packing | ~2,100 gas/read |
| Transient oracle caching | ~2,100 gas/hit |
| Packed timelocks | 66% slot reduction |
| Anchor-tree path walk (depth ≤ 4, ≤ 8 legs, no storage) | Storage-free path resolution |
| Bitmask hooks | 32 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):
| Error | Usage |
|---|---|
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*Libones (FeedMathLib,AnchorTreeLib,PoolIOLib,PoolHooksLib,TransientCacheLib,PoolConstantsLib) areinternaland 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.
15. Related Documentation
| Page | Covers |
|---|---|
| Inventory Management | Coverage, skew, pool rate |
| Liquidity Shaping | Preset depth curves |
| Anchor Path Pricing | Path composition, refFeedId |
| Spread & Fees | σ, confidence, staleness, the fee |
| Slippage & Price Impact | Execution costs, minAmountOut, deadline |
| Toxic Flow Mitigation | Flow guards |
| Parametrization | Parameter reference |
| Invariants | Fuzzing and formal-verification properties |
| Pool · Feed Oracle · Admin · Flash | Module references |
| Pool Hooks | Dual ledger, buffer, CompoundV2YieldHook |