← Documentation home
Build · Reference

Subgraph

GraphQL schema for historical activity, premium accrual, NAV reconciliation. Used by the Activity tab in the reference frontend.

Core entities

type Vault @entity {
  id: ID!                          # vault address (lowercase)
  asset: Bytes!
  underlyingVault: Bytes!          # the wrapped ERC4626
  seniorToken: Bytes!
  juniorToken: Bytes!
  protectionPremiumBps: BigInt!
  seniorNav: BigInt!
  juniorNav: BigInt!
  seniorTotalSupply: BigInt!
  juniorTotalSupply: BigInt!
  totalVaultShares: BigInt!
  lastPremiumAccrual: BigInt!
  depositsPaused: Boolean!
  ...
}
 
type Position @entity {
  id: ID!                          # vaultAddress-tranche-account
  vault: Vault!
  tranche: Tranche!                # SENIOR | JUNIOR
  account: Bytes!
  shares: BigInt!                  # current lcSEN/lcJUN balance
  cumulativeDeposited: BigInt!     # lifetime asset deposit
  cumulativeWithdrawn: BigInt!     # lifetime asset withdrawal
  noticeShares: BigInt!            # > 0 ⇒ withdrawal notice on file
  noticeExecutableAt: BigInt       # timestamp the notice unblocks
}
 
type Snapshot @entity {
  id: ID!                          # vaultAddress-timestamp
  vault: Vault!
  timestamp: BigInt!
  seniorNav: BigInt!
  juniorNav: BigInt!
  seniorSharePrice: BigInt!        # 1e18-scaled
  juniorSharePrice: BigInt!        # 1e18-scaled
  totalAssets: BigInt!
}

Position is keyed by (vault, tranche, account), one row per holder per side. Each user has at most one position per tranche per vault.

Activity entity

The frontend's Activity tab queries a single Activity union-style entity that subsumes every event type. Each row carries:

type Activity @entity {
  id: ID!                  # txHash-logIndex
  vault: Vault!
  kind: ActivityKind!
  timestamp: BigInt!
  account: Bytes
  receiver: Bytes
  txHash: Bytes!
  assets: BigInt           # primary amount, varies by kind
  shares: BigInt           # secondary amount for share-denominated events
  extra: ActivityExtra!    # kind-specific JSON-shaped fields
}
 
enum ActivityKind {
  SeniorDeposit
  JuniorDeposit
  SeniorWithdrawal
  JuniorWithdrawal
  SeniorWithdrawalNoticeRequested
  SeniorWithdrawalNoticeCancelled
  JuniorWithdrawalNoticeRequested
  JuniorWithdrawalNoticeCancelled
  PooledNavSynced
  ProtectionPremiumAccrued
  ProtectionPremiumRateScheduled
  ProtectionPremiumRateActivated
  DepositsPauseToggled
  SeniorDepositsPauseToggled
}

extra carries kind-specific fields like delta (for NAV sync), fromSeniorNav / toJuniorNav (for premium accrual), previousRateBps / newRateBps / effectiveAt (for rate scheduling), paused (for pause toggles), and executableAt (for notice requests). The frontend's notesCell and amountCell formatters branch on kind to pull the right field.

Common queries

Recent activity for a vault

query RecentActivity($vault: ID!, $first: Int!) {
  activities(
    where: { vault: $vault }
    orderBy: timestamp
    orderDirection: desc
    first: $first
  ) {
    id
    kind
    timestamp
    account
    receiver
    txHash
    assets
    shares
    extra
  }
}

A user's positions across all vaults

query UserPositions($user: Bytes!) {
  positions(where: { account: $user, shares_gt: 0 }) {
    vault {
      id
      asset
      protectionPremiumBps
      seniorSharePrice: derivedSeniorSharePrice  # see schema notes
      juniorSharePrice: derivedJuniorSharePrice
    }
    tranche
    shares
    noticeShares
    noticeExecutableAt
  }
}
query NavHistory($vault: ID!, $sinceTs: BigInt!) {
  snapshots(
    where: { vault: $vault, timestamp_gte: $sinceTs }
    orderBy: timestamp
    orderDirection: asc
    first: 1000
  ) {
    timestamp
    seniorSharePrice
    juniorSharePrice
    seniorNav
    juniorNav
  }
}

The frontend's useTrancheSnapshots hook uses the share-price column to derive realised APY from two consecutive snapshots: (price_t / price_t-1)^(1y / dt) − 1.

Morpho VaultV2 indexing

For indexing Morpho VaultV2 instances directly, see Morpho's official tooling at docs.morpho.org/tools.