Common queries

Copy-pasteable curl recipes for the queries integrators reach for first.

Every recipe below shows the query itself in a graphql block, a one-click link that opens Apollo Sandbox with the query pre-loaded, and the equivalent curl call. Replace the example vault address, chain ID, or user address with your own and the queries will return live data.

Recipes

#
Recipe
What it returns

1

Paginated vaults filtered by chain & visibility, with state and APR.

2

One vault with full current state, asset, and chain.

3

A user's share balance and pending/claimable deposits and redeems.

4

Recent on-chain events for a vault, typed via the TransactionData union.

5

Point-in-time reconstruction via stateAt.

6

Aggregate USD TVL across all Lagoon vaults.

Patterns from the production frontend worth copying.

List vaults on a chain

Top vaults on Ethereum by USD TVL, paginated, only those visible on the Lagoon frontend:

query ListVaults {
  vaults(
    first: 10
    skip: 0
    orderBy: totalAssetsUsd
    orderDirection: desc
    where: { chainId_eq: 1, isVisible_eq: true }
  ) {
    items {
      address
      name
      symbol
      state {
        totalAssetsUsd
        pricePerShareUsd
        yearlyApr { linearNetApr twrrNetApr }
      }
    }
    pageInfo { hasNextPage totalCount }
  }
}

Try in Apollo Sandbox →

Returns items (the vaults) plus pageInfo.totalCount for total match count and pageInfo.hasNextPage for paging.

Get a single vault by address

Fetch one vault with its current state, underlying asset, and chain:

Try in Apollo Sandbox →

state carries every live metric (TVL, supply, price-per-share, fees, sync mode, guardrails, roles). Pick only the fields you need.

Get a user's positions across vaults

A user's full position on a given chain — share balance, pending and claimable deposits, pending and claimable redeems — in one round trip:

Try in Apollo Sandbox →

This is the off-chain equivalent of the three on-chain calls described in Get a user position (balanceOf + maxMint + pendingRedeemRequest), plus the dollar value and the claimable-deposit current-price actualization.

Stream vault events

Most recent settlement events for a vault, with the event payload pulled from the TransactionData union via inline fragments:

Try in Apollo Sandbox →

TransactionData is a union — request only the variants you care about with ... on EventName fragments. The full list of event types is in the TransactionType enum (browsable in Sandbox). See Key data structures and epoch mechanism for the semantics of each event.

Historical vault state at a timestamp

Reconstruct a vault as it existed at a past Unix timestamp:

Try in Apollo Sandbox →

stateAt returns null (or a BAD_USER_INPUT error) for timestamps before the vault's first indexed state. For a time series of any of these fields, use stateHistory instead — see Conventions → Historical data.

Global Lagoon TVL

Try in Apollo Sandbox →

Returns a single Float — the aggregate USD TVL across all Lagoon vaults, sourced from DeFiLlama.

How the Lagoon dApp uses these queries

The production app.lagoon.finance frontend is built on exactly this API. A few patterns from that integration that are worth copying:

  • Server-side fetch, no client library. The dApp uses plain fetch with cache: 'no-store' from Next.js route handlers — no Apollo or urql. Letting the framework handle revalidation (ISR / revalidate directives) is simpler than maintaining a normalized cache, and the API returns whole entities anyway.

  • Compose queries from fragments. Vault listing pages and vault detail pages share a VaultFields fragment but pick different sub-fragments (VaultFieldsListLight skips APR data for fast homepage rendering; VaultFieldsDetail adds composition, fees, and roles). Define one fragment per logical view and interpolate into multiple queries.

  • isVisible_eq: true for frontend listings. Vaults flagged as not visible are still indexed and queryable, but should be filtered out of any list shown to end users.

  • Page with pageInfo.totalCount and hasNextPage. The dApp's transaction-history view does offset pagination with a small first value (e.g. 10) and uses totalCount to render the page count up-front.

  • Health-check on every request batch. Route handlers that fan out to multiple queries include _meta { lastIndexedBlocks { chainId number } } so the UI can surface "data may be stale" when a chain is more than ~1 hour behind.

  • Lowercased addresses in filters. Always normalize address inputs (e.g. with viem's getAddress / .toLowerCase()) before passing them to _eq / _in filters.

Last updated