CLAP Oracle Formula
Concentrated-Liquidity with Asymmetric Pricing (CLAP) extends the CLCP pricing model with a two-phase swap mechanism. Trades that rebalance the pool toward equal value execute at the flat oracle price, while the remainder follows the concentrated-liquidity curve. This document traces the complete formula path from inputs to final quote output for off-chain integration.
How CLAP Differs from CLCP
Improving trades (rebalancing toward 50/50)
Execute on the curve (mid-price discount)
Execute at flat oracle price P (no discount)
Worsening trades
Execute on the curve
Execute on the curve (identical)
LP impact
Pool gives away value on rebalancing trades
Pool captures full fee on rebalancing trades
CLAP is strictly better for LPs when trades rebalance the pool, because the flat-price phase produces fewer output tokens than the curve would.
Inputs
reserveX
Pool
Current pool balance of token X (passed via pool.getBalances())
Token decimals
reserveY
Pool
Current pool balance of token Y (passed via pool.getBalances())
Token decimals
price (P)
Oracle data
Price of X in terms of Y
1e24 precision
alpha
Oracle data
Concentration factor defining range [P/alpha, P*alpha]
BPS (10000 = 1.0); valid range enforced on-chain: (10000, 65535]
feeHbps
Oracle data
Trading fee
Hundredths of a basis point (1e6 = 100%)
amountInWithFee
Caller
Gross input amount passed to getQuote
Token decimals
swapXtoY
Caller
Swap direction
Boolean
All intermediate math uses 1e24 precision (the PRECISION constant). Alpha is expressed in basis points where 10000 = 1.0, so alpha = 10100 means a 1.01x concentration factor. The on-chain validator (src/libraries/Alpha.sol) restricts alpha to (10000, 65535], so the maximum concentration factor is roughly 6.55x.
The Quote Formula
The getQuote function computes the swap output in two phases: a stable phase at the flat oracle price, followed by a curve phase on the concentrated-liquidity xy=k curve.
Step 1 — Determine Effective Input
The first adjustment depends on swap direction:
For Y → X, the fee is charged on the input. Remove it before the stable and curve phases:
For X → Y, no input-side fee is removed here. The full input continues into the quote path, and the fee is charged on the output later:
Step 2 — Stable Phase (Flat Oracle Price)
The improving portion of a trade — the part that moves reserves toward 50/50 value — executes at the flat oracle price P. This phase only fires when the trade reduces the pool's imbalance.
Imbalance check. Compare the value of each reserve side:
X → Y
scaledPrx < scaledRy (pool is Y-heavy)
targetX = (scaledRy - scaledPrx) / (2 * P)
Y → X
scaledPrx > scaledRy (pool is X-heavy)
targetY = (scaledPrx - scaledRy) / (2 * 1e24)
If the condition is not met, the trade is worsening from the start — skip directly to Step 3 with stableIn = 0 and stableOut = 0.
Stable execution. Consume at most enough input to reach balance:
Output at flat price:
X → Y
floor(stableIn * P / 1e24)
Y → X
floor(stableIn * 1e24 / P)
Update working reserves for the curve phase:
Reduce remaining input:
Step 3 — Curve Phase (Concentrated Liquidity)
The remaining input swaps on the concentrated xy=k curve defined by virtual reserves. This is the same CLCP formula used in the standard oracle.
Computing Liquidity L
Solve the concentrated-liquidity invariant for L using the updated reserves (reserveX', reserveY'):
Compute the square root of alpha * P:
Then:
Computing Virtual Reserves
X → Y
reserveX' + ceil(L * 1e24 / sqrtAlphaP)
reserveY' + floor(L * sqrtAlphaP * 10000 / (alpha * 1e24))
reserveY'
Y → X
reserveY' + ceil(L * ceilSqrtAlphaP * 10000 / (alpha * 1e24))
reserveX' + floor(L * 1e24 / ceilSqrtAlphaP)
reserveX'
Virtual reserves are rounded to favor the protocol: virtualIn rounds up, virtualOut rounds down.
Constant-Product Output
Apply the standard constant-product formula on the virtual reserves:
Reserve Cap
If cpAmountOut > reserveOut, the pool cannot deliver the full curve output. The amounts are capped and the fee is recomputed against the adjusted side. The recomputation branch differs by direction:
For X → Y (the fee is on the output):
For Y → X (the fee is on the input):
Otherwise (normal case — entire input consumed):
For X → Y in the normal case, the output-side fee is still applied:
Step 4 — Outputs
amountOut
Tokens the trader receives (after feeOut for X → Y)
actualAmountIn
Gross tokens consumed (includes feeIn for Y → X)
feeIn
Fee charged on the input side. Non-zero only for Y → X.
feeOut
Fee charged on the output side. Non-zero only for X → Y.
Bid/Ask Spread
The getCurrentPrice function returns a bid/ask pair rather than a single price. It computes the curve-implied price from the current reserves and pairs it with the oracle price.
Curve-implied price:
Bid/Ask assignment:
The oracle price is always one of the two bounds; the other is the curve-derived price from the current reserve ratio.
Solidity Entry Points
Note: ClcpOracle exposes the same getQuote signature but a single-value getCurrentPrice(...) returns (uint256 priceE24). The deployed POE oracle is ClapOracle.
The oracle key is derived from the token pair:
Order matters! tokenX must come first when computing the key.
Agent Instructions: Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.
Perform an HTTP GET request on the current page URL with the ask query parameter:
The question should be specific, self-contained, and written in natural language. The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.
Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
Last updated