This guide explains how pricing works in OraclePool and how to track price changes. The key insight is that the execution price is not simply the oracle price — it's computed from both oracle data AND pool balances.
The Pricing Model
OraclePool uses a Concentrated Liquidity with Asymmetric Pricing (CLAP) model (an extension of the simpler CLCP curve). The price is determined by two components.
Oracle Data (Set by Operator)
The oracle operator sets these parameters:
Parameter
Description
Format
price (P)
Center/reference price of tokenX in tokenY
1e24 precision
alpha
Concentration factor
BPS (10000 = 1.0). Valid range: (10000, 65535]
feeHbps
Trading fee
Hundredths of a basis point (1e6 = 100%)
expiry
When the data expires (exclusive)
Unix timestamp (40-bit)
The alpha parameter defines the price range: [P/alpha, P*alpha]
For example, with alpha = 10100 (1.01 in BPS):
If oracle price P = 1.0, the actual price can range from ~0.99 to ~1.01
Pool Balances
The pool's tokenX / tokenY balances determine where within the price range the actual price sits. There is a single live quantity per token — the pool does not distinguish "reserves designated for trading" from "balances held"; everything held by the pool participates in pricing.
CLAP splits each swap into two phases:
Stable phase. If the trade brings the pool closer to 50/50 value (P · X ≈ Y), the improving portion executes at the flat oracle price P.
Curve phase. Any remaining input swaps along the concentrated-liquidity x·y = k curve using virtual reserves derived from real balances plus α.
Worsening trades skip the stable phase and execute entirely on the curve.
Oracle price alone is NOT the execution price. To compute the true price for a given trade size, use getQuote(...) on the pool (or call the oracle's getQuote(...) directly with the current balances). For a marginal bid/ask spread without an amount, use getCurrentPrice(key, balanceX, balanceY).
Reading Oracle Data
Computing the Oracle Key
Oracle data is stored by a key derived from the token pair:
Order matters! tokenX must come first when computing the key.
Getting the Data
Note: getData does not check expiry. To get just the price with expiry enforcement, call getPrice(key) instead.
Example usage:
Getting the Current Price
The deployed oracle is ClapOracle. It exposes a bid/ask spread rather than a single mid price:
The oracle price P is always one of the two bounds; the other is the curve-implied price derived from the current pool balances. Both are 1e24-scaled.
1
How getCurrentPrice works — step 1
Reads and validates (non-expired) the oracle data for key (price P, alpha).
2
How getCurrentPrice works — step 2
Uses the provided balances as reserveX / reserveY.
3
How getCurrentPrice works — step 3
Computes the curve-implied price from the balances and pairs it with P. The smaller of the two becomes the bid; the larger becomes the ask.
4
How getCurrentPrice works — step 4
Returns (bidPriceE24, askPriceE24) with 1e24 precision.
Example:
For an executable quote on a specific trade size (which includes the CLAP stable-phase mechanics and fees), use pool.getQuote(swapXtoY, amountIn) — see the Making a Swap page.
Price Format and Decimal Adjustment
The price returned is with 1e24 precision and represents the price of tokenX in terms of tokenY.
To get a human-readable price, adjust for token decimals:
Example — tokenX has 18 decimals and tokenY (USDC) has 6 decimals:
Another example — tokenX has 6 decimals and tokenY has 18 decimals:
Tracking Price Changes
Price can change from two sources:
Balance Changes (Events Available)
Pool balances change on swaps, deposits and withdrawals:
Notes:
actualAmountIn is the gross input including fee.
Only one of feeIn / feeOut is non-zero per swap: feeIn is in tokenIn for Y→X swaps; feeOut is in tokenOut (tokenY) for X→Y swaps. Both are forwarded to the FeeRewarder when set.
Oracle Data Changes (No Events)
The oracle's setData() function does NOT emit events. Its signature is parameter-less — the price/fee/alpha/expiry payload is read directly from calldata (see src/libraries/Oracle.sol in the repo for the layout). To track oracle changes you must either watch transactions calling setData() on the oracle contract and decode the raw calldata, or periodically poll getData(key).
TypeScript Example
Python Example
Key Takeaways
1
Price is a function of oracle data and pool balances
You need both to get the actual price. For trade-size-specific quotes use getQuote; for the marginal bid/ask spread use getCurrentPrice.
2
Oracle data has no events
setData() takes no parameters — the payload lives in the raw calldata. You must decode that calldata or periodically poll getData(key).
3
Balance changes have events
Watch Swap, Deposited and Withdrawn for balance-driven price changes.
4
Price precision is 1e24
Use humanPrice = priceE24 / 1e24 * 10^(decimalsX - decimalsY)
5
Alpha defines the allowed range
Actual price is bounded by [P/alpha, P*alpha]. Alpha is in BPS where 10000 = 1.0; the valid on-chain range is (10000, 65535].
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.