Method
What the number means, and how it is produced
Aquifer exists because a mid price tells you nothing about a fill. Everything below is reproducible with an RPC endpoint and the pool addresses.
Read the state from storage
Concentrated pools expose their state through getters, and every fork edits the shape of them, so return data is decoded word by word rather than through a strict ABI. Uniswap v4 has no pool contract at all — its state is a mapping entry inside the singleton, reached by computing the slot.
Half the equity liquidity on this chain is v4. Priced any other way, it is invisible.
// Uniswap v4 keeps every pool in one contract. // There is no pool address to call, so read the slot. base = keccak256(abi.encode(poolId, 6)) word = extsload(base) sqrtPriceX96 = word & ((1 << 160) - 1) tick = int24(word >> 160) lpFee = uint24(word >> 208)
Walk the ticks, do not model them
Treating the pool as a constant-product curve, or assuming the whole order fills inside the current tick, overstates the output — and the error is larger than the difference between venues you are trying to measure. So the swap is simulated the way the pool computes it: cross each initialized tick, take the fee, update liquidity, and round in the pool's direction at every step.
A large SPY clip crosses 43 initialized ticks on the tightest pool. Ignoring them is not a rounding error.
// Cross each initialized tick the way the pool does.
while (remaining > 0 && price != limit) {
next = nextInitializedTick(bitmap, tick, spacing)
step = computeSwapStep(price, next, liquidity, remaining, fee)
remaining -= step.amountIn + step.feeAmount
amountOut += step.amountOut
if (price == next) liquidity += liquidityNet[next]
}Allocate across venues by marginal price
One pool is rarely the best home for an entire order. Because output per unit falls as a pool is consumed, the allocation that maximises the total is the one that hands each slice to whichever pool pays most for that slice. Snapshots are simulated locally, so trying every allocation costs no extra network time.
Observed on a 250k USDG clip: 14 bps better than the best single venue.
// Hand each slice to whichever pool pays most for it.
for (slice of order) {
best = argmax(pools, p =>
simulate(p, allocated[p] + slice) - currentOut[p])
allocated[best] += slice
}Limits
What this deliberately does not do
A pricing tool is only useful if it is candid about its edges. These are the ones that would change how you read a quote.
Nothing here can move your money
There is no settlement contract, no approval to grant, and no signature requested. Aquifer computes what a trade is worth and stops there. A route is a description of the trade you would make, not an instrument that makes it.
A quote is a snapshot, not a promise
Pool state is read at a block. Anyone trading between that block and yours moves the price, so a fill matches a quote only to the extent the book has not changed. Nothing on this site enforces a minimum — enforcement is a property of the contract you send the trade to, and you are not sending it here.
Depth is loaded in a window
Tick data is fetched around spot rather than across the whole curve, because loading every tick of every pool for every quote would cost more than it is worth. An order large enough to run past that window is marked as a floor rather than quietly reported as a full fill.
Hooked pools are indicative
A Uniswap v4 pool with a hook can charge a fee decided at swap time or change the trade in ways tick data does not describe. Those pools are priced with the fee currently in storage and labelled hooked, because the alternative — dropping them — would hide real liquidity.
Discovery trusts an indexer
Which pools exist is read from DexScreener. It is the one input not taken from the chain, and it can only cause a pool to be missed, never mispriced: every number that affects a fill is read from contract storage afterwards.
Multi-hop is not implemented
Only direct pools between the two tokens are priced. An equity with no pool in your currency will not route through a bridge asset today, so a pair that should be reachable in two hops shows as unquotable rather than badly quoted.
Unaudited, and honest about it
This is read-only software with no contracts deployed and no audit. It can be wrong. Treat every number as a well-researched estimate of what a pool would do, verify anything that matters against the chain yourself, and never route real size on a single tool’s word — including this one.