The six that carry your V3 subgraph
Byte-identical to Uniswap V3, emitted by every pool type: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.
Handlers that need changing
uint8 (a four-bit denominator); these are shares out of ten thousand. A subgraph indexing this event needs its handler changed.
Fee accounting needs one more input: the pool’s fee coin. The trading events keep V3’s shape, but a pool can take every fee in one fixed token (feeToken(), announced by FeeTokenChanged). On such a pool, fee growth and protocol fees accrue in that token only — a V3 handler that infers the fee side from a Swap’s direction books half the trades on the wrong side.
New pool events (no V3 counterpart)
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
Graduated names the pool; the pool’s birth logs here). A pool born with a non-default fee coin emits FeeTokenChanged from its constructor, so that log lands before its PoolCreated.
The compatibility event
When governance has it switched on (compatibilityEvent(), toggled with CompatibilityEventChanged(bool)), the factory also emits a copy with Uniswap V3’s exact signature:
Governance and listing
RoleGranted / RoleRevoked on the factory, with role = POOL_CREATOR_ROLE().
Position manager
The V3 trio is signature-identical, down to the indexing: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.)
The manager also records a farmed position’s fee share when it is deferred, and when that deferred share is finally collected:
Plugin modules (index if you track these features)
- Limit orders:
OrderPlaced(owner, fillTick, sellingToken0, liquidity),OrderCancelled(...),OrdersFilled(fillTick, sellingToken0, epoch, amount0, amount1),OrderClaimed(...), andSettlementIncomplete(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)when the curve is retuned. The fee itself moves without an event: the plugin sets it as each swap begins and the pool stores it silently, so the fee a swap paid is the pool’sslot0().feeright after it. - Security:
StatusChanged(previous, current),GuardianChanged(guardian). - Active liquidity management:
RebalanceTriggered(centreTick)andRebalanceFailed(bytes reason)— a failed rebalance never blocks the swap, so this event is the only signal; index it if you track managed ranges. Configuration:RebalanceTargetChanged(target),RebalanceConditionChanged(fastPeriod, slowPeriod, threshold, minInterval, maxSpotDeviation). - 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
- Start from the deployment’s start blocks; discover pools from the factory’s native
PoolCreated— never the V3-shaped compatibility event — positions from the manager, launches from the launchpad factory. feeGrowthGlobal*X128may overflowuint256by design — index it as a wrapping counter, not a monotone value.- The emitted position range is always the pool-resolved one, so CP/STABLE logs never carry a caller’s fictional range.
- Protocol-fee accounting:
SetFeeProtocol(changed shape) +CollectProtocol+FeeTokenChanged(which side it accrues on).