Skip to main content

Overview

ClearingPriceLib is a pure Solidity library that handles batch settlement math for standard mode pools — pools with an underlying Uniswap v4 AMM that has real LP liquidity. It uses the AMM’s current spot price (slot0.sqrtPriceX96) as the uniform clearing price, determines which intents fill based on their slippage limits, calculates internal match amounts between opposing flow, and computes the residual to route through the AMM.
Standard mode only. This library is NOT used for curve (launch mode) pools. Curve pools use ConstantProductCurveLib.computeLaunchSettlement() instead, where the clearing price comes from the bonding curve’s spot price (Ve + E) / (Vt - S) and residual flow routes through the hook’s reserve rather than an AMM.

Two Settlement Paths

Standard ModeLaunch Mode (Geocurve)
LibraryClearingPriceLibConstantProductCurveLib
Clearing priceAMM spot price from slot0.sqrtPriceX96Curve spot price (Ve + E) / (Vt - S)
Residual routes toUniswap v4 AMM swapHook reserve (curve dispense/absorb)
RequiresReal LP liquidity in the poolNo LP — hook IS the market maker

Core Function

computeClearingPrice()

function computeClearingPrice(
    GeodeIntent[] memory buys,
    GeodeIntent[] memory sells,
    uint256 maxBatchSize,
    uint256 ammSpotPriceQ128,
    uint256 settlementFeeBps
) internal pure returns (
    SettlementResult memory result,
    bool[] memory buyFills,
    bool[] memory sellFills
)
Parameters:
  • buys — Buy intents, sorted by implicit limit price descending (most generous first)
  • sells — Sell intents, sorted by implicit limit price ascending (cheapest first)
  • maxBatchSize — Maximum allowed intents per side
  • ammSpotPriceQ128 — Current AMM spot price in Q128 fixed-point
  • settlementFeeBps — Fee charged on each filled intent’s input (in basis points)
Returns: SettlementResult with exact deposit-denominated quantities, plus boolean fill arrays.

Algorithm

1

Enforce Batch Size

Revert if either side exceeds maxBatchSize (default: 128, absolute max: 256).
2

Verify Sort Order

Buy intents must be sorted by descending limit price. Sell intents must be sorted by ascending limit price. Reverts with BuysNotSorted() or SellsNotSorted() if violated.Sort verification uses cross-multiplication to avoid division:
// Buys: buys[i-1].limitPrice >= buys[i].limitPrice
buys[i-1].amountIn * buys[i].minAmountOut >= buys[i].amountIn * buys[i-1].minAmountOut
3

Set Clearing Price

The clearing price is set to the AMM’s current spot price from the Uniswap v4 pool’s slot0.sqrtPriceX96. This is a v1 simplification — the clearing price equals the pool price at the moment of settlement, rather than being computed from order book crossing.
uint256 clearingPriceQ128 = ammSpotPriceQ128;
This price comes from the pool’s real LP liquidity. For standard pools, the AMM must have been seeded with liquidity for this price to be meaningful.
4

Determine Fills

For each intent, compute its implicit limit price and compare against the clearing price:
// Buy fills if: amountIn/minAmountOut >= clearingPrice
buyLimitQ128 = (buys[i].amountIn * Q128) / buys[i].minAmountOut;
buyFills[i] = (buyLimitQ128 >= clearingPriceQ128);

// Sell fills if: minAmountOut/amountIn <= clearingPrice
sellLimitQ128 = (sells[i].minAmountOut * Q128) / sells[i].amountIn;
sellFills[i] = (sellLimitQ128 <= clearingPriceQ128);
Intents that don’t meet the clearing price are skipped — their tokens are never pulled.
5

Compute Fees

Settlement fees are deducted from each filled intent’s input before any routing:
buyFeesAmt  = (totalBuyInput  * settlementFeeBps) / BPS_DENOMINATOR;
sellFeesAmt = (totalSellInput * settlementFeeBps) / BPS_DENOMINATOR;

netBuyInput  = totalBuyInput  - buyFeesAmt;
netSellInput = totalSellInput - sellFeesAmt;
6

Compute Internal Match

Convert net sell volume to buyer-side units and determine the match:
sellVolInQuote = (netSellInput * clearingPriceQ128) / Q128;

if (netBuyInput >= sellVolInQuote) {
    // Net buy pressure: all sellers matched
    internalMatch0 = sellVolInQuote;
    internalMatch1 = netSellInput;
    residualSwapAmount = netBuyInput - sellVolInQuote;
    residualZeroForOne = true;  // excess buys → AMM
} else {
    // Net sell pressure: all buyers matched
    internalMatch0 = netBuyInput;
    internalMatch1 = (netBuyInput * Q128) / clearingPriceQ128;
    residualSwapAmount = netSellInput - internalMatch1;
    residualZeroForOne = false; // excess sells → AMM
}

Key Properties

Pure Function

No state reads or writes. The entire computation is deterministic from its inputs.

Deposit-Denominated

All output quantities are in exact deposit units. No predictions about AMM output — the hook captures actual swap deltas at execution time.

Input-Side Fees

Fees are carved from gross input before matching. Net input drives all routing decisions.

Settler Competition

A malicious settler can omit intents to manipulate the clearing price. The mitigation is competition — any settler can submit a more complete batch. First valid settlement wins.

Source

ClearingPriceLib.sol

View the full source code on GitHub (~143 lines).