Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Subgraphs

Subgraphs index on-chain data from Euler V2 smart contracts and expose it through GraphQL. Euler's production subgraphs use a deliberately lightweight schema (euler-simple) designed to answer one question efficiently: which accounts have deposits or borrows in which vaults. This is the same source the Euler apps and the Euler SDK use for account position discovery.

The simple schema does not expose vault configuration, interest rates, APYs, prices, or health scores. For that data, take the vault and account addresses returned by the subgraph and query lens contracts or the Euler V3 API.

Source Code

The source code for the Euler simple subgraphs is open source and includes the GraphQL schema, entity definitions, and event handlers:

Available Networks and Endpoints

Copy a network's published GraphQL endpoint to query indexed vaults and account positions.

Loading network and subgraph publication metadata…

Catalog details

The table lists stable euler-simple publications. Network lifecycle comes from the registry. Production and deprecated networks are listed; staging, unlisted and unknown networks are hidden.

Metadata refreshes every minute. Failed refreshes remove catalog endpoint links rather than retaining stale results. Missing, retired, invalid and incompatible entries never use compatibility endpoints.

Only an initial catalog 404 exposes the collapsed compatibility links below. They are a static snapshot, not current publication or health evidence. Once a catalog publication has been observed, a later 404 cannot restore them.

Published means an endpoint is listed in the catalog; it does not certify current health, synchronization or production support. Deprecated networks can retain endpoints for discovering existing positions when exiting.

Deployment and Catalog Publication

Existing production deployments can populate the catalog without a new Goldsky deployment. An operator selects each existing release and runs catalog:import with a trusted chain checkpoint; the command discovers its URL through Goldsky's authenticated API and verifies the release, required queries and current latest selection. Add --dry-run to inspect the record without publishing. Imports omit unverified source/build metadata and require neither build receipts nor IPFS retrieval. See catalog operations.

Endpoint and deployment identity remain mandatory. Optional sourceCommit, startBlock and interfacesCommit describe build provenance only when established; their absence does not disable response identity checks. Publication does not certify source/build equality for imported deployments or ongoing service health.

Operators deploy Goldsky subgraphs manually with pnpm run deploy <network> from a clean commit while logged in to Goldsky. Deployment runs the build first; pnpm run build <network> prepares the manifest, generates Graph types, builds the subgraph and records its build receipt. The optional test or swap deployment argument appends that suffix to the deployment name. The operator-invoked catalog:promote helper validates one explicitly selected release, promotes its alias once, and publishes the catalog. Publication-only retries do not retag or redeploy. Retirement is an explicit operator action. A merge or CI run does not deploy or publish.

Catalog v1 records identify chain, family, channel, version, exact endpoint and deployment identity. Source commit, compiled start block and Interfaces commit are optional build metadata and are included only when established. Consumers select stable euler-simple entries with account-vault-discovery and vault-factory-lookup; candidates do not implicitly promote. Publication checks describe a point in time, not ongoing health. See the producer schema and tooling for the wire contract and operator instructions.

Adding a Network

  1. Deploy contracts and add the chain's addresses, name, and lifecycle to Interfaces. Docs visibility follows that lifecycle.
  2. Add the network entry to the subgraph repository's scripts/config.ts: chainId, network, eVaultFactory, eulerEarnFactory, optional securitizeFactory, and startBlock. Copy the two core factories from Interfaces addresses/<chainId>/CoreAddresses.json; include securitizeFactory from PeripheryAddresses.json only when it is nonzero. Set startBlock to the block in which the chain's EVC was deployed. This entry is the only subgraph configuration change needed for the new network.
  3. Commit the configuration, log in to Goldsky and run pnpm run deploy <network> from the clean checkout. Retain the build and its receipt for artifact-verified publication.
  4. Once the selected release has caught up, set RPC_URL_<chainId> and CATALOG_GIT_REMOTE, then run pnpm run catalog:promote <network> <version> stable <checkpoint-block> with a trusted, retained chain checkpoint. The catalog operations guide covers artifact access requirements and import when deployed artifacts cannot be retrieved. A new compatible stable entry joins the Docs table by numeric chain ID without an endpoint-list edit.
  5. Provision RPC and chain support in consuming applications, then opt in to catalog resolution and verify real reads. Catalog membership does not enable chains, change lifecycle or ONCHAIN_SDK_CHAINS, or configure V3, labels, ABIs, or deployment overrides. Use SDK 4.4.0 or a compatible newer release for imported catalog records with optional sourceCommit and startBlock; the standalone 4.3.0 parser requires both. Lite resolves its catalog server-side through the SDK's shared subgraph queries and catalog resolver.

Schema

The simple subgraph indexes vaults deployed by the EVK vault factory, the EulerEarn factory, and the Securitize collateral vault factory, and tracks account activity from vault Transfer, Borrow, and Repay events. It exposes three entities:

EntityKeyed byPurpose
Vaultvault addressAll indexed vaults and the factory that deployed them
TrackingActiveAccountaddress prefix (first 19 bytes)Lists of active deposit and borrow positions for all sub-accounts sharing a prefix
TrackingVaultBalanceaccount + vault (concatenated)Internal data structure used to maintain the active position lists — do not rely on it

The subgraph tells you where positions are, not their current size. TrackingVaultBalance holds raw values captured at the time of the last event and is immediately outdated — debt in particular accrues interest every second, but the subgraph only re-captures it when a new event touches the position. Read current balances, debt, and health through lens contracts or the Euler V3 API instead.

Address Prefixes

The key difference from the previous subgraphs: account activity is grouped by address prefix, not by account address. On Euler, every owner address controls 256 virtual sub-accounts via the EVC. All of them share the first 19 bytes of the address and differ only in the last byte. The subgraph keys TrackingActiveAccount by this shared prefix, so a single query returns positions across all of a user's sub-accounts.

To compute the prefix, lowercase the address and drop the last byte (the last two hex characters):

// 0x + 38 hex characters = first 19 bytes
const getAddressPrefix = (address) => address.toLowerCase().slice(0, 40);
 
getAddressPrefix("0x2B5A103a91B78E1352fDe6d3b7526bd932d1a2C4");
// => "0x2b5a103a91b78e1352fde6d3b7526bd932d1a2"

How to Get Active Positions of an Account

This is the primary use case for the simple subgraph, and the exact flow used by the Euler apps and the Euler SDK.

Step 1: Query the Subgraph by Address Prefix

Use the trackingActiveAccount query with the address prefix as the id:

query AccountPositions($prefix: ID!) {
  trackingActiveAccount(id: $prefix) {
    deposits
    borrows
  }
}

deposits and borrows are lists of active positions, each entry a concatenation of the sub-account address (20 bytes) and the vault address (20 bytes), e.g. 0x000000000000000000000000000000000000deade1ce9af672f8854845e5474400b6ddc7ae458a10.

To parse the entries in JavaScript:

import { getAddress } from "viem";
 
function parseEntry(entry) {
  return {
    subAccount: getAddress(entry.substring(0, 42)),
    vault: getAddress(`0x${entry.substring(42)}`),
  };
}
  • subAccount is the sub-account holding the position
  • vault is the vault the position is in

To look up several users, lowercase and deduplicate their prefixes, then send at most 1,000 unique prefixes per request. Set first: 1000 explicitly: the default result limit is 100, which can silently omit matching accounts in larger batches. Each prefix identifies at most one TrackingActiveAccount, so each bounded batch fits in one response:

query AccountVaults($ids: [String!]!) {
  trackingActiveAccounts(first: 1000, where: { id_in: $ids }) {
    id
    deposits
    borrows
  }
}

Pass the query above as query to this helper. It combines all batches before returning; a failed request rejects the operation instead of returning partial positions.

async function fetchAccountPositions(endpoint, owners, query) {
  const prefixes = [...new Set(
    owners.map((address) => address.toLowerCase().slice(0, 40)),
  )];
  const positions = [];
  for (let offset = 0; offset < prefixes.length; offset += 1000) {
    const response = await fetch(endpoint, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        query,
        variables: { ids: prefixes.slice(offset, offset + 1000) },
      }),
    });
    if (!response.ok) throw new Error(`Subgraph HTTP ${response.status}`);
    const result = await response.json();
    if (result.errors?.length) throw new Error("Subgraph query failed");
    positions.push(...result.data.trackingActiveAccounts);
  }
  return positions;
}

Step 2: Fetch Detailed Data Using Lens Contracts

Once you have the list of sub-accounts and vaults, use the lens contracts for detailed information:

  • Use AccountLens for account-level data (balances, health, rewards, etc.)
  • Use VaultLens for vault-specific details (configuration, caps, rates, etc.)

Step 3: Filter for Known Vaults

Use the known-vault endpoints to check whether a vault is known and to fetch its metadata (name, curator, deprecation status). This helps filter out unknown or experimental vaults — note that a vault being known is not a safety guarantee; only its initial configuration was reviewed.

Other Queries

List Indexed Vaults

query Vaults {
  vaults(first: 1000, orderBy: id, orderDirection: asc) {
    id
    factory
  }
}

Check Indexing Status

Use _meta to check how far the subgraph has indexed — useful for waiting until a recent transaction is reflected in query results:

{
  _meta {
    block {
      number
    }
  }
}