Skip to main content

The six that carry your V3 subgraph

Byte-identical to Uniswap V3, emitted by every pool type:
STABLE pools emit the same shapes: ranges as MIN_TICK/MAX_TICK, and the Swap tick derived from the price — in tick space, zero means exactly 1:1, so emitting a literal zero would report a wrong price on every stable swap.

The one changed handler

V3’s four fields are uint8 (a four-bit denominator); these are shares out of ten thousand. A subgraph indexing this event needs its handler changed. Everything else on the pool that V3 has is untouched.

New pool events (no V3 counterpart)

STABLE adds AmplificationChanged(uint32 old, uint32 new) and AmplificationRampStarted(uint32 start, uint32 target, uint32 endTime). There is no IncreaseObservationCardinalityNext on the pool — the TWAP is a plugin, and that event lives on the oracle module.

Factory

PoolCreated is not V3’s signature — pool discovery handlers need the new shape. This is the stream that catches launchpad graduations too: the launchpad’s own Graduated event names the pool, but the pool’s birth logs here.

Position manager

The V3 trio is signature-identical, down to the indexing:
One addition that will silently corrupt a V3-shaped position tracker if unhandled:
A position can move to a new range keeping its token id — no DecreaseLiquidity + Collect + IncreaseLiquidity sequence describes it on the manager. Without a handler, a repositioned NFT appears to sit at its old ticks forever. (The pool underneath still emits its own Burn/Collect/Mint, and optionally a Swap, in the same transaction.)

Plugin modules (index if you track these features)

  • Limit orders: OrderPlaced(owner, fillTick, sellingToken0, liquidity), OrderCancelled(...), OrdersFilled(fillTick, sellingToken0, epoch, amount0, amount1), OrderClaimed(...), and SettlementIncomplete(settledThrough, target) — a swap can cross more ticks than one transaction settles; unsettled orders still rest and still fill later.
  • Oracle: IncreaseObservationCardinalityNext(old, new) on the oracle module.
  • Dynamic fees: FeeCurveChanged(baseFee, maxFee, sensitivity, twapPeriod); the pool’s own FeeChanged fires as the fee moves.
  • Security: StatusChanged(previous, current).
  • Farming: IncentiveCreated(virtualPool, pool, rewardTokens), Entered/Exited(virtualPool, tokenId, ...), RewardAdded, RateChanged.
  • Vaults: VaultCreated(vault, pool, owner, tickLower, tickUpper) on the vault factory; Deposited/Withdrawn/Rebalanced, PositionOpened(tokenId), and the reward ledger events (Harvested, RewardClaimed) on each vault.

Indexer rules of thumb

  1. Start from the deployment’s start blocks; discover pools from PoolCreated, positions from the manager, launches from the launchpad factory.
  2. feeGrowthGlobal*X128 may overflow uint256 by design — index it as a wrapping counter, not a monotone value.
  3. The emitted position range is always the pool-resolved one, so CP/STABLE logs never carry a caller’s fictional range.
  4. Protocol-fee accounting: SetFeeProtocol (changed shape) + CollectProtocol.