> For the complete documentation index, see [llms.txt](https://docs.kumbaya.xyz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.kumbaya.xyz/developers/dex-integration/reading-pools.md).

# Reading pools and positions

Three ways to read pool state: directly via RPC (cheapest, freshest), via the Hasura indexer (best for ranges + history), and via the Exchange API (curated, cached).

## Pool address from token + fee tier

Always derive the address with Kumbaya's pool init code hash, not Uniswap's. The `@kumbaya_xyz/v3-sdk` does it for you:

```ts
import { Pool, FeeAmount } from '@kumbaya_xyz/v3-sdk'
import { Token, ChainId } from '@kumbaya_xyz/sdk-core'

const A = new Token(ChainId.MEGAETH, '0x...', 18, 'A')
const B = new Token(ChainId.MEGAETH, '0x...', 6,  'B')

const poolAddress = Pool.getAddress(A, B, FeeAmount.MEDIUM) // 0.3%
```

If you implement the derivation yourself, see [**Pool Init Code Hash**](/developers/dex-integration/pool-init-code-hash.md).

## Reading current state via RPC

The two most useful reads are `slot0` (current price + tick) and `liquidity` (active liquidity at the current tick).

```ts
import { createPublicClient, http, parseAbi } from 'viem'

const RPC = 'https://mainnet.megaeth.com/rpc'
const client = createPublicClient({ transport: http(RPC) })

const poolAbi = parseAbi([
  'function slot0() view returns (uint160 sqrtPriceX96, int24 tick, uint16 observationIndex, uint16 observationCardinality, uint16 observationCardinalityNext, uint8 feeProtocol, bool unlocked)',
  'function liquidity() view returns (uint128)',
  'function token0() view returns (address)',
  'function token1() view returns (address)',
  'function fee() view returns (uint24)',
  'function tickSpacing() view returns (int24)',
])

const [slot0, liquidity, token0, token1, fee] = await Promise.all([
  client.readContract({ address: poolAddress, abi: poolAbi, functionName: 'slot0' }),
  client.readContract({ address: poolAddress, abi: poolAbi, functionName: 'liquidity' }),
  client.readContract({ address: poolAddress, abi: poolAbi, functionName: 'token0' }),
  client.readContract({ address: poolAddress, abi: poolAbi, functionName: 'token1' }),
  client.readContract({ address: poolAddress, abi: poolAbi, functionName: 'fee' }),
])

const [sqrtPriceX96, tick] = slot0
console.log({ tick, sqrtPriceX96, liquidity })
```

`slot0()` returns `sqrtPriceX96` (a `Q64.96` fixed-point number). To convert to a human-readable price the standard formula is:

```ts
// price of token1 per token0, ignoring decimals:
const ratio = Number(sqrtPriceX96) / 2 ** 96
const rawPrice = ratio * ratio

// Adjust for token decimals to get human-readable token1 / token0 price:
const adjustedPrice = rawPrice * 10 ** (token0.decimals - token1.decimals)
```

You can also reach for the V3 SDK if you want typed `Price` / `Token` / `Pool` objects:

```ts
import { Pool } from '@kumbaya_xyz/v3-sdk'
import { TickMath } from '@kumbaya_xyz/v3-sdk'

// Returns the sqrt(price) * 2^96 at a given tick, as JSBI:
const sqrtPriceFromTick = TickMath.getSqrtRatioAtTick(tick)
```

## Tick liquidity via TickLens

For range UIs and depth charts you'll want the populated ticks around the current tick. Use `TickLens`:

```ts
const TICK_LENS = '0x9c22f028e0a1dc76EB895a1929DBc517c9D0593e' // mainnet

const tickLensAbi = parseAbi([
  'function getPopulatedTicksInWord(address pool, int16 tickBitmapIndex) view returns ((int24 tick, int128 liquidityNet, uint128 liquidityGross)[])',
])

const wordIndex = Math.floor(currentTick / tickSpacing / 256)
const populated = await client.readContract({
  address: TICK_LENS,
  abi: tickLensAbi,
  functionName: 'getPopulatedTicksInWord',
  args: [poolAddress, wordIndex],
})
```

Loop adjacent word indices to walk further from current tick.

## Reading positions

Each LP position is an NFT held by `NonfungiblePositionManager`:

```ts
const NFPM = '0x2b781C57e6358f64864Ff8EC464a03Fdaf9974bA' // mainnet

const positionAbi = parseAbi([
  'function positions(uint256 tokenId) view returns (uint96 nonce, address operator, address token0, address token1, uint24 fee, int24 tickLower, int24 tickUpper, uint128 liquidity, uint256 feeGrowthInside0LastX128, uint256 feeGrowthInside1LastX128, uint128 tokensOwed0, uint128 tokensOwed1)',
  'function ownerOf(uint256 tokenId) view returns (address)',
])

const position = await client.readContract({
  address: NFPM,
  abi: positionAbi,
  functionName: 'positions',
  args: [tokenId],
})
```

`tokensOwed0` / `tokensOwed1` show fees that have been "settled" but not yet collected. To see *uncollected* fees (including unsettled fee growth), the cleanest path is to construct a `Position` object via the SDK with current pool state.

## Querying historical state via the indexer

For anything time-bounded - TVL over a week, swap volume, position changes - go through the [Hasura GraphQL endpoint](/developers/resources/indexer.md):

```graphql
query PoolDay($poolId: String!) {
  PoolDayData(
    where: { pool_id: { _eq: $poolId } }
    order_by: { date: desc }
    limit: 30
  ) {
    date
    volumeUSD
    feesUSD
    tvlUSD
    token0Price
    token1Price
  }
}
```

Or current pool state with relationships joined in:

```graphql
query Pool($id: String!) {
  Pool_by_pk(id: $id) {
    address
    feeTier
    liquidity
    sqrtPrice
    tick
    totalValueLockedUSD
    volumeUSD
    token0 { symbol decimals }
    token1 { symbol decimals }
  }
}
```

Pool IDs are `address-chainId` (e.g. `0xabc...-4326`).

## Curated reads via the Exchange API

If you don't want to run the queries yourself:

```
GET https://exchange.kumbaya.xyz/api/v1/pools/list?chainId=4326&limit=50
GET https://exchange.kumbaya.xyz/api/v1/pools/{poolId}
GET https://exchange.kumbaya.xyz/api/v1/pools/{poolId}/timeseries?timeframe=days&limit=30
GET https://exchange.kumbaya.xyz/api/v1/pools/{poolId}/ticks
```

Cached, paginated, and rate-limit friendly - use these for browser-grade UIs. See [**Pools endpoints**](/developers/apis/exchange-api/pools.md).

## Picking the right path

| Task                                              | Best path               |
| ------------------------------------------------- | ----------------------- |
| One-time pool state read                          | RPC                     |
| Range / depth chart for one pool                  | RPC + TickLens          |
| Time-series, aggregations, joins                  | Hasura indexer          |
| Browser-grade UI feeding pool list / token detail | Exchange API            |
| Position health for a known `tokenId`             | RPC `positions()` + SDK |
