Uniswap v3 Subgraphs: Uniswap vs Messari - how to choose

Confused about which Uniswap v3 subgraph to use? This guide breaks down the difference between the official Uniswap v3 subgraph and Messari’s Uniswap v3 subgraph —covering schema design, mappings, and use cases for each so you can choose the right subgraph for your dApp, dashboard, or research.

Uniswap v3 Subgraphs: Uniswap vs Messari - how to choose

When developers first start building on the blockchain, one of the most common challenges is extracting reliable, structured data from smart contracts. Direct RPC calls to blockchain nodes are fine for one-off reads, but this approach quickly hits bottlenecks when, for example, you need to query events across blocks, filter transactions, or analyze liquidity movements.

This is where Subgraphs come in. Subgraphs are a way to index blockchain data into structured, queryable entities that apps or dashboards can consume and display on the front-end. But many developers new to subgraphs get stuck:

  • What’s the difference between the manifest, the schema, and the mappings?
  • Why are there multiple subgraphs for the same protocol, like Uniswap v3’s official subgraph and Messari’s curated version?
  • Which one should I use?

This guide walks through those questions step by step, with Uniswap v3 as the example.

What is a Subgraph?

A subgraph is a blueprint that tells an indexer:

  • What to watch: which contracts, events, or functions to listen to.
  • How to store it: entities and relationships defined in GraphQL.
  • How to transform it: mappings that convert raw event data into structured entities.

Once deployed, the subgraph continuously ingests blockchain events and stores them in a way you can query via GraphQL.

The three core components

The manifest (subgraph.yaml)

The manifest is the frame of your subgraph. It specifies:

  • Contract addresses (ex. Uniswap v3 Factory, Pools).
  • Events to track (PoolCreated, Swap, Mint, Burn).

Which mapping file handles those events.

Example (Uniswap v3 Factory):

dataSources:
  - kind: ethereum/contract
    name: UniswapV3Factory
    network: mainnet
    source:
      address: "0x1F98431c8aD98523631AE4a59f267346ea31F984"
      abi: Factory
    mapping:
      kind: ethereum/events
      apiVersion: 0.0.7
      language: wasm/assemblyscript
      entities:
        - Pool
      abis:
        - name: Factory
          file: ./abis/Factory.json
      eventHandlers:
        - event: PoolCreated(indexed address,indexed address,indexed uint24,int24,address)
          handler: handlePoolCreated

Note: the fee parameter in PoolCreated is indexed.

The schema (schema.graphql)

The schema defines your data model, which is the entities you’ll query.

For Uniswap v3, typical entities include:

type Pool @entity {
  id: ID!
  token0: Token!
  token1: Token!
  feeTier: BigInt!
  swaps: [Swap!]! @derivedFrom(field: "pool")
}

type Swap @entity {
  id: ID!
  pool: Pool!
  sender: Bytes!
  recipient: Bytes!
  amount0: BigDecimal!
  amount1: BigDecimal!
  timestamp: BigInt!
}

Each Pool tracks fee tiers, tokens, and swaps. Each Swap captures trade details. The @derivedFrom directive creates efficient one-to-many relationships without storing duplicate data.

The mappings (AssemblyScript)

Mappings are the translation layer between raw blockchain events and your schema. They’re written in AssemblyScript (TypeScript-like), compiled to WebAssembly.

Example: when Uniswap emits a Swap event:

export function handleSwap(event: SwapEvent): void {
  let swap = new Swap(event.transaction.hash.toHex() + "-" + event.logIndex.toString());
  swap.pool = event.address.toHex();
  swap.sender = event.params.sender;
  swap.recipient = event.params.recipient;
  swap.amount0 = event.params.amount0.toBigDecimal();
  swap.amount1 = event.params.amount1.toBigDecimal();
  swap.timestamp = event.block.timestamp;
  swap.save();
}

Now you can query swaps by pool, by user, or over a period of time - something that’s impractical with raw RPCs unless you build and operate custom indexing infrastructure.

Uniswap v3 Subgraphs: Official vs. Messari

To query Uniswap v3 data, there are two main Subgraphs developers use:

  • Official Uniswap v3 Subgraph
  • Messari’s Uniswap v3 Subgraph

Both index the same smart contract, but their goals and implementations differ significantly.

Official Uniswap v3 Subgraph

Purpose: Track Uniswap v3 at the protocol level, exposing all core mechanics.

Structure:

  • Focuses on entities like Pool, Swap, Position.
  • Preserves Uniswap-specific details: ticks, sqrtPriceX96, fee tiers.

Great for: Developers building Uniswap-specific apps or research tools.

Schema example (protocol-centric):

type Pool @entity {
  id: ID!
  token0: Token!
  token1: Token!
  feeTier: BigInt!
  liquidity: BigInt!
  sqrtPriceX96: BigInt!
  tick: Int
}

Mappings directly write what happened on-chain:

export function handlePoolCreated(event: PoolCreated): void {
  let pool = new Pool(event.params.pool.toHex());
  pool.token0 = event.params.token0.toHex();
  pool.token1 = event.params.token1.toHex();
  pool.feeTier = event.params.fee;
  pool.save();
}

Messari’s Uniswap v3 Subgraph

Purpose: Provide analytics-ready, normalized data across DeFi protocols.

Structure:

  • Adapts Uniswap data to Messari’s standardized DEX schema.
  • Entities use LiquidityPool instead of Pool.
  • Adds derived metrics (USD values, TVL, cumulative volume).
  • Creates time-series entities like daily snapshots.

Great for: Dashboards, research, and cross-protocol comparisons.

Schema example (analytics-centric):

type LiquidityPool @entity {
  id: ID!
  inputTokens: [Token!]!
  totalValueLockedUSD: BigDecimal!
  cumulativeVolumeUSD: BigDecimal!
  dailySnapshots: [PoolDailySnapshot!]! @derivedFrom(field: "pool")
}

type PoolDailySnapshot @entity {
  id: ID!
  pool: LiquidityPool!
  dailyVolumeUSD: BigDecimal!
  # revenue/fee fields vary by schema version
  timestamp: BigInt!
}

Mappings normalize raw data into USD and roll it up into snapshots:

export function handleSwap(event: SwapEvent): void {
  let pool = LiquidityPool.load(event.address.toHex())!;
  let amountUSD = getUSDValue(event.params.amount0, pool.inputTokens[0])
                .plus(getUSDValue(event.params.amount1, pool.inputTokens[1]));

  let snapshot = getOrCreatePoolDailySnapshot(pool, event.block.timestamp);
  snapshot.dailyVolumeUSD = snapshot.dailyVolumeUSD.plus(amountUSD);
  snapshot.save();
}

Messari’s subgraphs use a shared pricing module to normalize raw token amounts into USD values. This is part of their standardized subgraph framework, as documented in the Messari Subgraphs GitHub repository. The pricing logic is centralized in their codebase docs/ORACLES.md, which defines how values like TVL, volume, and fees are denominated in USD.

Comparing Uniswap vs. Messari Subgraphs

Uniswap v3 Official Messari Uniswap v3
Goal Standard data Analytics-based metrics
Schema Pools, swaps, ticks, positions LiquidityPool with TVL & snapshots
Data Raw on-chain events Derived metrics (USD, time-series)
Mappings Direct event → entity Event → entity & normalized metrics
Use case Uniswap-specific apps & research Cross-protocol dashboards, analytics

How do I choose which Uniswap Subgraph to use?

Use Uniswap’s official subgraph if you’re:

  • Building liquidity management tools.
  • Researching fee tiers, ticks, or positions.
  • Need exact protocol details.

Use Messari’s subgraph if you’re:

  • Comparing Uniswap to Aave, Curve, or Sushiswap.
  • Building dashboards that need USD values and time series.
  • Want analytics without reinventing the wheel.

In practice, many developers use both to expose different data. 

The takeaway

Understanding subgraphs breaks down to these key concepts:

  • YAML = what to watch: The manifest specifies which contracts and events to index.
  • Schema = how data is structured: GraphQL entities define your queryable data model.
  • Mappings = how raw events become usable entities: AssemblyScript transforms blockchain data into structured information.
  • Uniswap v3 subgraph = protocol-native truth: Raw, detailed on-chain data.
  • Messari’s subgraph = normalized analytics: Standardized metrics for cross-protocol analysis.

TL;DR

  • Start with the official Uniswap V3 Subgraph to learn the mechanics.
  • Move to Messari’s Uniswap V3 Subgraph if you need standardized metrics for dashboards or research.

The power of subgraphs lies in transforming unstructured blockchain data into a format developers can easily query and build upon. Whether you need protocol-specific depth or standardized breadth, both approaches solve the fundamental challenge of making Web3 data accessible and actionable.

About Ormi

Ormi is the next-generation data layer for Web3, purpose-built for real-time, high-throughput applications like DeFi, gaming, wallets, and on-chain infrastructure. Its hybrid architecture ensures sub-30ms latency and up to 4,000 RPS for live subgraph indexing, sub-10ms responses across 100+ API schemas, and a powerful SQL engine for historical and AI-ready data.

With 99.9% uptime and deployments across ecosystems representing $50B+ in TVL and $100B+ in annual transaction volume, Ormi is trusted to power the most demanding production environments without throttling or delay.