Developer Hub
🔮 For applications
Guides & Tutorials
Advanced integration
Tutorial: Add Live to Existing dApp
Step 2: Data Retrieval

Adding Live. Step 2: Live Data Retrieval

Here, we'll explain how to display live games and their markets. You can find more undercover details in the related documentation: Live Data Retrieval.

The data structure is nearly identical to the one used in the main Subgraph for prematch core contracts.

ℹ️

Key differences in the entities structure comparing to prematch subgraphs:

  • Removed all entities and events related to bets (bets, freebets, expresses) and contracts (cores, liquidity pools).
  • Removed selection entity and its relations.
  • Entity condition doesn't have an isExpressForbidden field.
  • Event GameShifted changed to GameUpdated (triggers by changing game status and/or start time).
  • Event ConditionShifted completely removed.

Load live games

If you've utilized fields excluded from the Live subgraph, we recommend splitting data fetching into games and conditions. This allows you to reuse game/sport queries for both Prematch and Live requests.

Here's an example of a universal hook to retrieve events from both Prematch and Live feeds:

import { universalGamesQuery } from './query'
 
export const useGames = (props) => {
  const {
    startsAt,
    isLive,
    ...yourRestVariablesLikeSportSlug,
  } = props
 
  const { prematchClient, liveClient } = useApolloClients()
  const client = isLive ? liveClient! : prematchClient!
 
  const variables = {
    ...yourRestVariablesLikeSportSlug,
  }
 
  if (isLive) {
    // LIVE: _lt suffix
    variables.where.startsAt_lt = startsAt
  }
  else {
    // PREMATCH: _gt suffix + LP filter
    variables.where.startsAt_gt = startsAt
    variables.where.liquidityPool = _lp_contract_address.toLowerCase()
  }
 
  return useQuery(universalGamesQuery, {
    variables,
    client,
  })
}

Apply this condition tweak to every fetching event data query.

Load markets

Because of the difference between Live and Prematch condition entities, it's not possible to reuse the Prematch query. You'll need to create a new one.

Take a look at the source code of the SDK's useGameMarkets (opens in a new tab) hook. It utilizes useConditions (opens in a new tab) hook to fetch conditions from the Live or Prematch feed depending on a game status, and then combines them in markets. To streamline the handling of both Prematch and Live conditions in the SDK, we're modifying these entities to have the same fields.

Let's examine the key changes in the SDK hooks for fetching prematch and live conditions:

See full code: https://github.com/Azuro-protocol/sdk/blob/v3.1.0/src/hooks/useGameMarkets.ts (opens in a new tab)

useGameMarkets.ts
/* ... */
const groupMarkets = (conditions: ConditionsQuery['conditions'], gameId: string, lpAddress: Address): GameMarkets => {
  const outcomesByMarkets: OutcomesByMarkets = {}
  const result: OutcomeRowsByMarket = {}
  const sportId = conditions[0]!.game.sport.sportId
 
  conditions.forEach((condition) => {
    const { conditionId, outcomes: rawOutcomes, status } = condition
    const coreAddress = (condition as PrematchConditionsQuery['conditions'][0]).core?.address || liveHostAddress
    const isExpressForbidden = (condition as PrematchConditionsQuery['conditions'][0]).isExpressForbidden ?? true
 
    rawOutcomes.forEach((rawOutcome) => {
      const { outcomeId } = rawOutcome
      const odds = (rawOutcome as PrematchConditionsQuery['conditions'][0]['outcomes'][0]).odds
      const betTypeOdd = dictionaries.outcomes[outcomeId]
 
      if (!betTypeOdd) {
        console.warn(`betTypeOdd not found for "outcomeId: ${outcomeId}"`)
 
        return
      }
      const marketKey = getMarketKey(outcomeId)
      const marketName = getMarketName({ outcomeId })
      const marketDescription = getMarketDescription({ outcomeId })
      const selectionName = getSelectionName({ outcomeId, withPoint: true })
 
      const outcome: MarketOutcome = {
        coreAddress: coreAddress,
        lpAddress: lpAddress,
        conditionId,
        outcomeId,
        selectionName,
        status,
        gameId,
        isExpressForbidden,
      }
 
      if (odds) {
        outcome.odds = +odds
      }
 
      /* ... */
    })
  })
  /* ... */
}
 
export const useGameMarkets = (props: Props) => {
  const { gameId, gameStatus, filter } = props
 
  const { contracts } = useChain()
  const { loading, conditions, error } = useConditions({
    gameId,
    filter,
    isLive: gameStatus === GameStatus.Live,
    livePollInterval: 2000,
  })
  /* ... */
}
/* see full code: https://github.com/Azuro-protocol/sdk/blob/v3.1.0/src/hooks/useGameMarkets.ts */
💡

Check out the SDK's implementation of the game markets fetching hook for both Prematch and Live feeds: