> ## Documentation Index
> Fetch the complete documentation index at: https://docs.livepeer.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Network Metrics

> Every Livepeer Network metric on the Explorer, what it means, and how to compute the institutional metrics analysts and investors need.

export const BorderedBox = ({children, variant = "default", padding = "var(--lp-spacing-4)", borderRadius = "var(--lp-spacing-px-8)", margin = "", accentBar = "", style = {}, className = "", ...rest}) => {
  const variants = {
    default: {
      border: "1px solid var(--lp-color-border-default)",
      backgroundColor: "var(--lp-color-bg-card)"
    },
    accent: {
      border: "1px solid var(--lp-color-accent)",
      backgroundColor: "var(--lp-color-bg-card)"
    },
    muted: {
      border: "1px solid var(--lp-color-border-default)",
      backgroundColor: "transparent"
    }
  };
  const accentBarColors = {
    accent: "var(--lp-color-accent)",
    positive: "var(--green-9)"
  };
  return <div data-docs-bordered-box="" data-accent-bar={accentBarColors[accentBar] ? "" : undefined} className={className} style={{
    ...variants[variant],
    padding: padding,
    borderRadius: borderRadius,
    ...margin ? {
      margin
    } : {},
    ...accentBarColors[accentBar] ? {
      position: "relative",
      '--accent-bar-color': accentBarColors[accentBar]
    } : {},
    ...style
  }} {...rest}>
      {children}
    </div>;
};

export const ScrollableDiagram = ({children, title = '', maxHeight = '500px', minWidth = '100%', showControls = false, className = '', style = {}, ...rest}) => {
  const buildDiagramKey = (currentTitle = '', currentClassName = '') => {
    const source = `${currentTitle}|${currentClassName}|scrollable-diagram`;
    let hash = 0;
    for (let index = 0; index < source.length; index += 1) {
      hash = hash * 31 + source.charCodeAt(index) >>> 0;
    }
    return `docs-diagram-${hash.toString(36)}`;
  };
  const diagramKey = buildDiagramKey(title, className);
  const zoomName = `${diagramKey}-zoom`;
  const zoomLevels = [{
    label: '75%',
    value: 0.75
  }, {
    label: '100%',
    value: 1
  }, {
    label: '125%',
    value: 1.25
  }, {
    label: '150%',
    value: 1.5
  }];
  const containerStyle = {
    overflow: 'auto',
    maxHeight,
    border: '1px solid var(--lp-color-border-default)',
    borderRadius: "8px",
    padding: "var(--lp-spacing-4)",
    background: 'var(--lp-color-bg-card)',
    position: 'relative'
  };
  return <div className={className} style={{
    position: 'relative',
    marginBottom: "var(--lp-spacing-4)",
    ...style
  }} {...rest}>
      {title && <p style={{
    textAlign: 'center',
    fontStyle: 'italic',
    color: 'var(--lp-color-text-secondary)',
    marginBottom: "var(--lp-spacing-2)",
    fontSize: '0.875rem'
  }}>
          {title}
        </p>}

      {showControls ? <style>{`
          [data-docs-diagram-key="${diagramKey}"] [data-docs-diagram-content] {
            transform: scale(1);
            transform-origin: top left;
            width: max-content;
          }
          ${zoomLevels.map(zoomLevel => `
          #${diagramKey}-${zoomLevel.label.replace('%', '')}:checked ~ [data-docs-diagram-shell] [data-docs-diagram-content] {
            transform: scale(${zoomLevel.value});
          }
          #${diagramKey}-${zoomLevel.label.replace('%', '')}:checked ~ [data-docs-diagram-controls] label[for="${diagramKey}-${zoomLevel.label.replace('%', '')}"] {
            background: var(--lp-color-accent);
            color: var(--lp-color-on-accent);
            border-color: var(--lp-color-accent);
          }`).join('\n')}
        `}</style> : null}

      {showControls ? zoomLevels.map(zoomLevel => {
    const inputId = `${diagramKey}-${zoomLevel.label.replace('%', '')}`;
    return <input key={inputId} id={inputId} type="radio" name={zoomName} defaultChecked={zoomLevel.value === 1} style={{
      position: 'absolute',
      opacity: 0,
      pointerEvents: 'none'
    }} />;
  }) : null}

      <div data-docs-diagram-key={diagramKey} data-docs-diagram-shell style={containerStyle}>
        <div data-docs-diagram-content style={{
    minWidth,
    transformOrigin: 'top left',
    width: 'max-content'
  }}>
          {children}
        </div>
      </div>

      {showControls ? <div data-docs-diagram-controls style={{
    display: 'flex',
    justifyContent: 'flex-end',
    alignItems: 'center',
    gap: "var(--lp-spacing-2)",
    marginTop: "var(--lp-spacing-2)",
    flexWrap: 'wrap'
  }}>
          <span style={{
    fontSize: "0.75rem",
    color: 'var(--lp-color-text-muted)',
    marginRight: 'auto'
  }}>
            Scroll to pan
          </span>
          {zoomLevels.map(zoomLevel => {
    const inputId = `${diagramKey}-${zoomLevel.label.replace('%', '')}`;
    return <label key={inputId} htmlFor={inputId} style={{
      background: 'transparent',
      color: 'var(--lp-color-text-secondary)',
      border: '1px solid var(--lp-color-border-default)',
      borderRadius: "4px",
      padding: '4px 10px',
      cursor: 'pointer',
      fontSize: "0.75rem",
      fontWeight: '600'
    }}>
                {zoomLevel.label}
              </label>;
  })}
        </div> : null}
    </div>;
};

export const DynamicTableV2 = ({tableTitle = null, headerList = [], itemsList = [], monospaceColumns = [], columnWidths = {}, columnConfig = {}, showSeparators = false, margin, className = '', style = {}, ...rest}) => {
  if (!headerList.length) {
    return <div>No headers provided</div>;
  }
  const tableRef = useRef(null);
  const [measuredColumnWidths, setMeasuredColumnWidths] = useState({});
  const measureFitColumns = () => {
    const tableElement = tableRef.current;
    if (!tableElement) {
      return;
    }
    const nextWidths = headerList.reduce((accumulator, header, index) => {
      const config = columnConfig?.[header] || ({});
      if (!config.fitContent) {
        return accumulator;
      }
      const contentNodes = tableElement.querySelectorAll(`[data-docs-column-key="${index}"] [data-docs-fit-content]`);
      let maxContentWidth = 0;
      contentNodes.forEach(node => {
        const width = Math.ceil(node.getBoundingClientRect().width);
        if (width > maxContentWidth) {
          maxContentWidth = width;
        }
      });
      if (maxContentWidth > 0) {
        accumulator[header] = `${maxContentWidth + 16}px`;
      }
      return accumulator;
    }, {});
    setMeasuredColumnWidths(currentWidths => {
      const currentEntries = Object.entries(currentWidths);
      const nextEntries = Object.entries(nextWidths);
      if (currentEntries.length === nextEntries.length && nextEntries.every(([header, width]) => currentWidths[header] === width)) {
        return currentWidths;
      }
      return nextWidths;
    });
  };
  useLayoutEffect(() => {
    measureFitColumns();
  }, [headerList, itemsList, columnConfig]);
  useEffect(() => {
    const tableElement = tableRef.current;
    if (!tableElement || typeof ResizeObserver === 'undefined') {
      return undefined;
    }
    const resizeObserver = new ResizeObserver(() => {
      measureFitColumns();
    });
    resizeObserver.observe(tableElement);
    if (tableElement.parentElement) {
      resizeObserver.observe(tableElement.parentElement);
    }
    return () => {
      resizeObserver.disconnect();
    };
  }, [headerList, itemsList, columnConfig]);
  const fitHeaders = headerList.filter(header => columnConfig?.[header]?.fitContent);
  const hasMeasuredFitColumns = fitHeaders.length === 0 || fitHeaders.every(header => Boolean(measuredColumnWidths[header]));
  const getColumnStyle = (header, isMonospace = false) => {
    const config = columnConfig?.[header] || ({});
    const fitContent = Boolean(config.fitContent);
    const fluid = Boolean(config.fluid);
    const nowrap = Boolean(config.nowrap) || fitContent || isMonospace;
    const preferredWidth = columnWidths[header];
    const measuredWidth = measuredColumnWidths[header];
    return {
      ...fitContent && measuredWidth ? {
        width: measuredWidth,
        minWidth: measuredWidth,
        maxWidth: measuredWidth
      } : {},
      ...!fitContent && !fluid && preferredWidth ? {
        minWidth: preferredWidth
      } : {},
      ...nowrap ? {
        whiteSpace: 'nowrap'
      } : {
        wordWrap: 'break-word',
        overflowWrap: 'break-word'
      }
    };
  };
  const getColumnTrackStyle = header => {
    const config = columnConfig?.[header] || ({});
    const fitContent = Boolean(config.fitContent);
    const fluid = Boolean(config.fluid);
    const preferredWidth = columnWidths[header];
    const measuredWidth = measuredColumnWidths[header];
    if (fitContent && measuredWidth) {
      return {
        width: measuredWidth,
        minWidth: measuredWidth,
        maxWidth: measuredWidth
      };
    }
    if (fluid) {
      return {};
    }
    if (preferredWidth) {
      return {
        width: preferredWidth
      };
    }
    return {};
  };
  const renderCellContent = (header, content) => {
    const config = columnConfig?.[header] || ({});
    if (!config.fitContent) {
      return content;
    }
    return <div data-docs-fit-content style={{
      display: 'inline-flex',
      alignItems: 'center',
      whiteSpace: 'nowrap',
      width: 'max-content',
      maxWidth: 'none'
    }}>
        {content}
      </div>;
  };
  return <div className={className} style={style} {...rest}>
      {tableTitle && <div style={{
    fontStyle: 'italic',
    margin: 0
  }}>
          <strong>{tableTitle}</strong>
        </div>}
      <div style={{
    overflowX: 'auto',
    ...margin != null && ({
      margin
    })
  }} role="region" tabIndex={0} aria-label={tableTitle ? `Scrollable table: ${tableTitle}` : 'Scrollable table'}>
        <table ref={tableRef} data-docs-dynamic-table-v2 style={{
    width: '100%',
    tableLayout: hasMeasuredFitColumns ? 'fixed' : 'auto',
    borderCollapse: 'collapse',
    fontSize: '0.9rem',
    marginTop: 0
  }}>
          <colgroup>
            {headerList.map((header, index) => <col key={index} style={getColumnTrackStyle(header)} />)}
          </colgroup>
          <thead>
            <tr style={{
    backgroundColor: 'var(--lp-color-accent)',
    color: 'var(--lp-color-on-accent)',
    borderBottom: '1px solid var(--lp-color-border-default)'
  }}>
              {headerList.map((header, index) => <th key={index} data-docs-column-key={index} style={{
    padding: '10px 8px',
    textAlign: 'left',
    fontWeight: '600',
    color: 'var(--lp-color-on-accent)',
    verticalAlign: 'top',
    ...getColumnStyle(header)
  }}>
                  {renderCellContent(header, header)}
                </th>)}
            </tr>
          </thead>
          <tbody>
            {itemsList.filter(item => showSeparators || !item?.__separator).map((item, rowIndex) => item?.__separator ? <tr key={rowIndex} style={{
    backgroundColor: 'var(--lp-color-accent)',
    color: 'var(--lp-color-on-accent)',
    borderBottom: '1px solid var(--lp-color-accent)'
  }}>
                    <td colSpan={headerList.length} style={{
    padding: '6px 8px',
    fontWeight: '700',
    color: 'var(--lp-color-on-accent)',
    letterSpacing: '0.01em'
  }}>
                      {(item[headerList[0]] ?? item.Category) ?? 'Category'}
                    </td>
                  </tr> : <tr key={rowIndex} style={{
    borderBottom: '1px solid var(--lp-color-border-default)'
  }}>
                    {headerList.map((header, colIndex) => {
    const value = (item[header] ?? item[header.toLowerCase()]) ?? '-';
    const isMonospace = monospaceColumns.includes(colIndex);
    return <td key={colIndex} data-docs-column-key={colIndex} style={{
      padding: '8px 8px',
      fontFamily: isMonospace ? 'monospace' : 'inherit',
      verticalAlign: 'top',
      ...getColumnStyle(header, isMonospace)
    }}>
                          {renderCellContent(header, isMonospace ? <code>{value}</code> : value)}
                        </td>;
  })}
                  </tr>)}
          </tbody>
        </table>
      </div>
    </div>;
};

export const LinkArrow = ({href, label, description, newline = true, borderColor, className = '', style = {}, ...rest}) => {
  const linkArrowStyle = {
    display: 'inline-flex',
    alignItems: 'center',
    justifyContent: 'center',
    gap: "var(--lp-spacing-1)",
    width: 'fit-content',
    ...borderColor && ({
      borderColor
    })
  };
  return <span className={className} style={style} {...rest}>
      {newline && <br />}
      <span style={linkArrowStyle}>
        <a href={href} target="_blank" rel="noopener noreferrer">
          {label}
        </a>
        <Icon icon="arrow-up-right" size={14} color="var(--lp-color-accent)" />
      </span>
      {description && description}
      {description && <div style={{
    height: "var(--lp-spacing-3)"
  }} />}
    </span>;
};

export const CustomDivider = ({color = "var(--lp-color-border-default)", middleText = "", spacing = "default", style = {}, className = "", ...rest}) => {
  const spacingPresets = {
    default: {
      margin: "24px 0"
    },
    overlap: {
      margin: "-1rem 0 -1rem 0"
    },
    tight: {
      margin: "0 0 -1rem 0"
    },
    section: {
      margin: "0 0 -2rem 0"
    },
    sectionOverlap: {
      margin: "-1rem 0 -2rem 0"
    },
    deepOverlap: {
      margin: "-1rem 0 -1.5rem 0"
    }
  };
  const spacingStyle = spacingPresets[spacing] || spacingPresets.default;
  return <div role="separator" aria-orientation="horizontal" className={className} style={{
    display: "flex",
    alignItems: "center",
    ...spacingStyle,
    fontSize: style?.fontSize || "16px",
    height: "fit-content",
    ...style
  }} {...rest}>
      <span style={{
    marginRight: "var(--lp-spacing-px-8)",
    opacity: 0.2
  }}>
        <Icon icon="/snippets/assets/logos/Livepeer-Logo-Symbol-Theme.svg" />
      </span>
      <div style={{
    flex: 1,
    height: "1px",
    background: "var(--lp-color-border-default)",
    opacity: 0.4
  }}></div>
      {middleText && <>
          <Icon icon="circle" size={2} />
          <span style={{
    margin: "0 8px",
    fontWeight: "bold",
    color: color,
    opacity: 0.7
  }}>
            {middleText}
          </span>
          <Icon icon="circle" size={2} />
        </>}
      <div style={{
    flex: 1,
    height: "1px",
    background: "var(--lp-color-border-default)",
    opacity: 0.4
  }}></div>
      <span style={{
    marginLeft: "var(--lp-spacing-px-8)",
    opacity: 0.2
  }}>
        <span style={{
    display: "inline-block",
    transform: "scaleX(-1)"
  }}>
          <Icon icon="/snippets/assets/logos/Livepeer-Logo-Symbol-Theme.svg" />
        </span>
      </span>
    </div>;
};

export const Quote = ({children, className = "", style = {}, ...rest}) => {
  const quoteStyle = {
    fontSize: "1rem",
    textAlign: 'center',
    opacity: 1,
    fontStyle: 'italic',
    color: 'var(--lp-color-accent)',
    border: '1px solid var(--lp-color-border-default)',
    borderRadius: "8px",
    padding: "var(--lp-spacing-4)",
    margin: '1rem 0',
    ...style
  };
  return <blockquote className={className} style={quoteStyle} {...rest}>{children}</blockquote>;
};

export const Subtitle = ({style = {}, text, children, variant = 'default', fontSize = '', fontWeight = '', fontStyle = '', marginTop = '', marginBottom = '', color = '', className = '', ...rest}) => {
  const renderInlineCode = (value, keyPrefix) => {
    return value.split(/(`[^`]+`)/g).map((segment, index) => {
      if (segment.startsWith('`') && segment.endsWith('`')) {
        return <code key={`${keyPrefix}-code-${index}`}>{segment.slice(1, -1)}</code>;
      }
      return segment;
    });
  };
  const renderInlineMarkup = (value, keyPrefix = 'subtitle') => {
    if (typeof value !== 'string') {
      return value;
    }
    return value.split(/(\*\*[\s\S]+?\*\*)/g).map((segment, index) => {
      if (segment.startsWith('**') && segment.endsWith('**')) {
        const inner = segment.slice(2, -2);
        return <strong key={`${keyPrefix}-strong-${index}`}>
            {renderInlineCode(inner, `${keyPrefix}-strong-${index}`)}
          </strong>;
      }
      return renderInlineCode(segment, `${keyPrefix}-${index}`);
    });
  };
  const renderContent = (value, keyPrefix) => {
    if (Array.isArray(value)) {
      return value.map((item, index) => renderContent(item, `${keyPrefix}-${index}`));
    }
    return renderInlineMarkup(value, keyPrefix);
  };
  const variants = {
    default: {
      fontSize: '1rem',
      fontStyle: 'italic',
      color: 'var(--lp-color-accent)',
      marginBottom: 0
    },
    changelog: {
      fontSize: '0.8rem',
      fontStyle: 'normal',
      fontWeight: 700,
      color: 'var(--lp-color-text-primary)',
      marginBottom: 0
    }
  };
  const base = variants[variant] || variants.default;
  return <span className={className} style={{
    ...base,
    ...fontSize ? {
      fontSize
    } : {},
    ...fontWeight ? {
      fontWeight
    } : {},
    ...fontStyle ? {
      fontStyle
    } : {},
    ...marginTop ? {
      marginTop
    } : {},
    ...marginBottom ? {
      marginBottom
    } : {},
    ...color ? {
      color
    } : {},
    ...style
  }} {...rest}>
      {renderContent(text, 'text')}
      {renderContent(children, 'children')}
    </span>;
};

export const CustomCardTitle = ({icon, title, variant = "card", iconSize, style = {}, className = "", ...rest}) => {
  const variants = {
    card: {
      display: 'flex',
      alignItems: 'center',
      gap: "var(--lp-spacing-2)",
      marginBottom: "var(--lp-spacing-3)",
      color: 'var(--lp-color-text-primary)',
      fontSize: '1rem',
      fontWeight: 600
    },
    accordion: {
      display: 'inline-flex',
      alignItems: 'center',
      gap: "var(--lp-spacing-2)"
    },
    tab: {
      display: 'inline-flex',
      alignItems: 'center',
      gap: '0.4rem',
      fontSize: '0.875rem'
    }
  };
  const sizes = {
    card: 20,
    accordion: 18,
    tab: 14
  };
  const size = iconSize || sizes[variant] || 20;
  const baseStyle = variants[variant] || variants.card;
  return variant === 'card' ? <div className={className} style={{
    ...baseStyle,
    ...style
  }} {...rest}>
      {typeof icon === 'string' ? <Icon icon={icon} size={size} color="var(--lp-color-accent)" /> : icon}
      {title}
    </div> : <span className={className} style={{
    ...baseStyle,
    ...style
  }} {...rest}>
      {typeof icon === 'string' ? <Icon icon={icon} size={size} color="var(--lp-color-accent)" /> : icon}
      {title}
    </span>;
};

<Quote>
  The Livepeer Explorer at [explorer.livepeer.org](https://explorer.livepeer.org/) shows network state in real time. This page defines every metric on the Explorer and the formulas to compute the standard institutional metrics (FDV, P/S ratio, Nakamoto coefficient, annualised inflation) from subgraph data.
</Quote>

<CustomDivider style={{ margin: 0, marginBottom: '-2rem' }} />

## Round Status

A round is one period during which Orchestrators can call `reward` once, parameters can be changed, and a new Active Set is fixed. Rounds on Arbitrum One are approximately 21 hours long, set by `roundLength` measured in L1 blocks. Each round closes when its block count is reached; the next round begins when an Orchestrator calls `RoundsManager.initializeRound()`.

<DynamicTableV2
  headerList={['Metric', 'What it shows', 'Why it matters']}
  itemsList={[
{
  Metric: <Subtitle variant="changelog">**Current Round**</Subtitle>,
  'What it shows': 'Integer round ID, increments by 1 each round transition.',
  'Why it matters': 'The round number is the unit of time on Livepeer. Reward calls, stake changes, and parameter updates are all keyed to it.',
},
{
  Metric: <Subtitle variant="changelog">**Initialized / Locked**</Subtitle>,
  'What it shows': '`Initialized` once any Orchestrator has called `initializeRound()`. `Locked` in the final blocks of a round when bond changes and parameter updates are no longer accepted.',
  'Why it matters': 'Indicates whether stake changes and reward calls are currently possible. A round that stays uninitialised signals the Active Set is not actively running.',
},
{
  Metric: <Subtitle variant="changelog">**Blocks Remaining / Time Remaining**</Subtitle>,
  'What it shows': 'L1 blocks until the round ends, plus an approximate time estimate using a 12-second L1 block average.',
  'Why it matters': 'Tells Delegators how long they have to bond, change delegate, or wait for a reward call. Tells Orchestrators how long they have to call `reward` before missing the round.',
},
{
  Metric: <Subtitle variant="changelog">**Fees (current round)**</Subtitle>,
  'What it shows': 'ETH redeemed via winning tickets in the current round, with USD-equivalent in the tooltip at recent prices.',
  'Why it matters': 'Real-time demand signal. A round with high fees means jobs are being delivered and paid for right now.',
},
{
  Metric: <Subtitle variant="changelog">**Rewards (current round)**</Subtitle>,
  'What it shows': 'LPT minted by Orchestrators that have called `reward()` this round, displayed as `claimed / mintable LPT`.',
  'Why it matters': 'Shows how much of the round\'s scheduled inflation has been claimed. A reward call ratio below 100% means some active Orchestrators have skipped the round, leaving LPT unminted.',
},
{
  Metric: <Subtitle variant="changelog">**Total Supply**</Subtitle>,
  'What it shows': 'Current LPT in existence, the ERC-20 `totalSupply()` of the LPT contract on Arbitrum One.',
  'Why it matters': 'The denominator of every supply-relative metric on this page. Foundation of FDV and market cap.',
},
{
  Metric: <Subtitle variant="changelog">**Supply Change (1Y)**</Subtitle>,
  'What it shows': 'Percent change in Total Supply over the past 365 days.',
  'Why it matters': 'Realised annual inflation, after `reward()` skip rate is taken into account. Differs from the configured inflation rate when reward calls are missed.',
},
]}
/>

<CustomDivider style={{ margin: '-1rem 0 -2rem 0' }} />

## Activity Metrics

Fee volume is denominated in ETH (Gateways pay in ETH via probabilistic micropayment tickets) and converted to USD at the price oracle value at redemption. Estimated usage converts fee volume into minutes of compute delivered using a per-pixel reference price; methodology last updated 21 August 2023 ([forum post](https://forum.livepeer.org/t/livepeer-explorer-minutes-estimation-methodology/2140)).

<DynamicTableV2
  headerList={['Metric', 'What it shows', 'Why it matters']}
  itemsList={[
{
  Metric: <Subtitle variant="changelog">**Fees Paid (1d / 7d, USD)**</Subtitle>,
  'What it shows': 'Daily or weekly aggregate of all winning ticket redemptions across the network, in USD.',
  'Why it matters': 'Direct demand-side measure. The Explorer chart toggles between 1d and 7d aggregation.',
},
{
  Metric: <Subtitle variant="changelog">**Estimated Usage (1d / 7d, minutes)**</Subtitle>,
  'What it shows': 'Estimated minutes of network compute delivered, derived from fee volume and a per-pixel reference price.',
  'Why it matters': 'Translates fee dollars into real work done. Useful for sizing the network in terms of compute, not just money.',
},
{
  Metric: <Subtitle variant="changelog">**Total Fee Volume (lifetime, ETH)**</Subtitle>,
  'What it shows': 'Cumulative ETH paid through winning ticket settlements across the protocol\'s history on Arbitrum One. Subgraph field: `Protocol.totalVolumeETH`.',
  'Why it matters': 'Lifetime demand. The numerator for any cumulative revenue analysis.',
},
{
  Metric: <Subtitle variant="changelog">**Total Fee Volume (lifetime, USD)**</Subtitle>,
  'What it shows': 'Cumulative USD-equivalent of redeemed tickets, computed at the price oracle value on each redemption. Subgraph field: `Protocol.totalVolumeUSD`.',
  'Why it matters': 'Lifetime revenue in dollar terms. The standard input for an annualised P/S ratio.',
},
{
  Metric: <Subtitle variant="changelog">**Annualised Fee Revenue (computed)**</Subtitle>,
  'What it shows': 'Sum of `Day.volumeUSD` across the last 365 days. Computed from the `days` subgraph entity.',
  'Why it matters': 'The standard "TTM revenue" figure for crypto valuation comparisons.',
},
]}
/>

<iframe src="https://dune.com/embeds/4073378/6884213" height="420" width="100%" style={{ border: 'none', borderRadius: '8px' }} title="Livepeer transcoding tickets and fees, weekly" />

Live: weekly transcoding fee volume from Rick Staa's Dune dashboard. Source: [`dune.com/queries/4073378`](https://dune.com/queries/4073378). For real-time daily data, see the [Explorer homepage](https://explorer.livepeer.org/).

<CustomDivider style={{ margin: '-1rem 0 -2rem 0' }} />

## Economic Metrics

Three subgraph fields fully describe the LPT supply system: `totalSupply`, `inflation`, `participationRate`. They form a closed feedback loop. When participation falls below the target rate, inflation rises; when participation exceeds target, inflation falls. The loop is defined in `BondingManager` and runs once per round.

<ScrollableDiagram title="The Participation-Inflation Feedback Loop" maxHeight="400px">
  ```mermaid theme={"theme":{"light":"github-light","dark":"dark-plus"}}
  %%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#1a1a1a', 'primaryTextColor': '#E0E4E0', 'primaryBorderColor': '#2b9a66', 'lineColor': '#2b9a66', 'secondaryColor': '#0d0d0d', 'tertiaryColor': '#1a1a1a', 'background': '#0d0d0d', 'fontFamily': "Inter, 'Inter Fallback', -apple-system, system-ui" }}}%%
  flowchart LR
      classDef default fill:#1a1a1a,color:#E0E4E0,stroke:#2b9a66,stroke-width:2px

      PR["Participation Rate<br/>= totalActiveStake / totalSupply"]
      Target["Target rate<br/>(governance set)"]
      Inf["Inflation<br/>(per round)"]
      Mint["Mintable LPT<br/>(this round)"]
      Supply["Total Supply<br/>(next round)"]

      PR -->|below target| Inf
      PR -->|above target| Inf
      Target -.->|comparison| PR
      Inf --> Mint
      Mint --> Supply
      Supply -.->|new denominator| PR
  ```
</ScrollableDiagram>

<DynamicTableV2
  headerList={['Metric', 'What it shows', 'Why it matters']}
  itemsList={[
{
  Metric: <Subtitle variant="changelog">**Total Supply**</Subtitle>,
  'What it shows': 'LPT in existence. ERC-20 `LivepeerToken.totalSupply()`. Increases each round by `mintableTokens` claimed.',
  'Why it matters': 'The supply denominator. Both FDV and market cap derive from this.',
},
{
  Metric: <Subtitle variant="changelog">**Circulating Supply (computed)**</Subtitle>,
  'What it shows': 'Total Supply minus Treasury Balance minus unbonded-but-locked LPT. Livepeer does not have a vested-team component, so circulating ≈ total minus treasury for most analyses.',
  'Why it matters': 'The numerator for market cap. The supply that can move.',
},
{
  Metric: <Subtitle variant="changelog">**Inflation Rate (per round)**</Subtitle>,
  'What it shows': 'LPT minted per round as a fraction of total supply. Subgraph field: `Protocol.inflation` (PPM-billion).',
  'Why it matters': 'The raw input to all inflation calculations. Adjusts each round by `inflationChange` based on participation.',
},
{
  Metric: <Subtitle variant="changelog">**Annualised Inflation (computed)**</Subtitle>,
  'What it shows': '`inflation × rounds-per-year`. With ~21-hour rounds on Arbitrum One, approximately 417 rounds per year.',
  'Why it matters': 'The dilution rate a token holder experiences before any treasury cut.',
},
{
  Metric: <Subtitle variant="changelog">**Net Inflation (computed)**</Subtitle>,
  'What it shows': 'Annualised Inflation × (1 − `treasuryRewardCutRate`). The portion of new LPT that reaches stakers after the treasury takes its share.',
  'Why it matters': 'Real dilution to a Delegator. The treasury cut reduces inflation reaching the Active Set without changing the headline rate.',
},
{
  Metric: <Subtitle variant="changelog">**Participation Rate**</Subtitle>,
  'What it shows': '`totalActiveStake / totalSupply`, the percent of LPT bonded to active Orchestrators. Subgraph field: `Protocol.participationRate`.',
  'Why it matters': 'Both a security signal (more stake means more economic exposure backing work) and a yield modulator (drives inflation up or down).',
},
{
  Metric: <Subtitle variant="changelog">**Supply Change (1Y)**</Subtitle>,
  'What it shows': 'Realised annual change in Total Supply, including reward-call skip rate. Shown directly on the Explorer Round Status panel.',
  'Why it matters': 'Differs from configured inflation when Orchestrators miss reward calls. The honest measure of LPT dilution holders see.',
},
{
  Metric: <Subtitle variant="changelog">**LPT Price in ETH**</Subtitle>,
  'What it shows': 'On-chain price oracle value used for ticket settlement and yield calculations. Subgraph field: `Protocol.lptPriceEth`.',
  'Why it matters': 'The exchange rate that converts ETH fees into LPT-equivalent yield, and the input Gateways use to size winning tickets.',
},
{
  Metric: <Subtitle variant="changelog">**FDV (computed)**</Subtitle>,
  'What it shows': '`LPT spot price (USD) × Total Supply`. LPT spot price is sourced from CoinGecko, Coinbase, or any major exchange.',
  'Why it matters': 'Standard valuation comparable. FDV is more relevant than market cap for Livepeer because there is no team-vested overhang to discount.',
},
{
  Metric: <Subtitle variant="changelog">**P/S Ratio (computed)**</Subtitle>,
  'What it shows': '`FDV / Annualised Fee Revenue (USD)`. The standard valuation multiple for revenue-generating protocols.',
  'Why it matters': 'Comparable to traditional equity multiples and to other revenue-generating crypto protocols (Lido, MakerDAO, Aave).',
},
]}
/>

<CustomDivider style={{ margin: '-1rem 0 -2rem 0' }} />

## Decentralisation Metrics

Concentration metrics are computed from the Orchestrator subgraph entity. Active Set size and Delegator count are direct subgraph fields; concentration ratios and the Nakamoto coefficient are derived from the Orchestrator stake distribution.

<DynamicTableV2
  headerList={['Metric', 'What it shows', 'Why it matters']}
  itemsList={[
{
  Metric: <Subtitle variant="changelog">**Active Orchestrators**</Subtitle>,
  'What it shows': 'Count of Orchestrators in the current Active Set. Subgraph field: `Protocol.activeTranscoderCount`. Capped at `numActiveTranscoders` (currently 100 {/* REVIEW: confirm cap pre-merge */}).',
  'Why it matters': 'The number of independent operators that run the network. Active Set turnover signals competitive pressure on stake.',
},
{
  Metric: <Subtitle variant="changelog">**Delegators**</Subtitle>,
  'What it shows': 'Total distinct Delegator addresses across the network. Subgraph field: `Protocol.delegatorsCount`.',
  'Why it matters': 'The size of the staking community. Growth here signals broader LPT distribution.',
},
{
  Metric: <Subtitle variant="changelog">**Average Stake per Orchestrator (computed)**</Subtitle>,
  'What it shows': '`totalActiveStake / activeTranscoderCount`.',
  'Why it matters': 'Indicates whether stake is evenly distributed across the Active Set or concentrated in a few large operators.',
},
{
  Metric: <Subtitle variant="changelog">**Average Stake per Delegator (computed)**</Subtitle>,
  'What it shows': '`totalActiveStake / delegatorsCount`.',
  'Why it matters': 'Distinguishes a network of many small Delegators from one of a few whales.',
},
{
  Metric: <Subtitle variant="changelog">**Top 10 Stake Concentration (computed)**</Subtitle>,
  'What it shows': 'Sum of `totalStake` for the top 10 Orchestrators divided by `totalActiveStake`. Computed from the Orchestrators subgraph query.',
  'Why it matters': 'Standard concentration measure. Lower is more decentralised.',
},
{
  Metric: <Subtitle variant="changelog">**Nakamoto Coefficient (computed)**</Subtitle>,
  'What it shows': 'Minimum number of Orchestrators needed to control 33% of `totalActiveStake`. Walk Orchestrators desc by stake until cumulative > 33%.',
  'Why it matters': 'The standard institutional decentralisation metric. A higher Nakamoto coefficient means more Orchestrators must coordinate to influence governance or active-set dynamics.',
},
]}
/>

<CustomDivider style={{ margin: '-1rem 0 -2rem 0' }} />

## Staking Metrics

Forecasted Yield on the Orchestrator list is computed live from network parameters (`inflation`, `inflationChange`, `totalActiveStake`, `lptPriceEth`), the Orchestrator's parameters (`rewardCut`, `feeShare`, recent fee volume, reward call ratio), and configurable assumptions (time horizon, delegation amount, factors, future inflation). The result is an estimate, not a guarantee.

<DynamicTableV2
  headerList={['Metric', 'What it shows', 'Why it matters']}
  itemsList={[
{
  Metric: <Subtitle variant="changelog">**Total Staked (LPT)**</Subtitle>,
  'What it shows': 'Sum of bonded LPT across all active Orchestrators. Subgraph field: `Protocol.totalActiveStake`.',
  'Why it matters': 'The denominator of staking ratio. Excludes stake bonded to inactive Orchestrators.',
},
{
  Metric: <Subtitle variant="changelog">**Staking Ratio**</Subtitle>,
  'What it shows': 'Identical to Participation Rate: `totalActiveStake / totalSupply`. Named differently in different contexts.',
  'Why it matters': 'Standard institutional comparable. Ethereum, Solana, and most PoS chains report this number.',
},
{
  Metric: <Subtitle variant="changelog">**Number of Stakers**</Subtitle>,
  'What it shows': 'Identical to Delegators count: `Protocol.delegatorsCount`.',
  'Why it matters': 'Standard institutional comparable. Often paired with Staking Ratio in coverage reports.',
},
{
  Metric: <Subtitle variant="changelog">**Forecasted Yield**</Subtitle>,
  'What it shows': 'Estimated rewards plus fees over a chosen time horizon if the reader were to delegate a chosen LPT amount to a specific Orchestrator. Computed live in the Explorer using the formula in the [yield calculation reference](https://docs.livepeer.org/delegators/reference/yield-calculation).',
  'Why it matters': 'Lets a Delegator compare Orchestrators on a single yield number. The popover decomposes it into LPT rewards and ETH fees so the source of yield is visible.',
},
{
  Metric: <Subtitle variant="changelog">**Yield Assumptions**</Subtitle>,
  'What it shows': 'The configurable inputs to Forecasted Yield: time horizon (6M, 1Y, 2Y, 3Y, 4Y), delegation amount (LPT), factors (LPT only, ETH only, or both), inflation change (none, positive, negative).',
  'Why it matters': 'Yield is sensitive to these assumptions. The Explorer surfaces them so a reader can see whether a high yield rests on optimistic inputs.',
},
]}
/>

<CustomDivider style={{ margin: '-1rem 0 -2rem 0' }} />

## Orchestrator Columns

Reward Cut and Fee Cut apply to different income streams and are commonly confused. Reward Cut applies to LPT inflation; Fee Cut applies to ETH fees. The Orchestrator list at [explorer.livepeer.org/Orchestrators](https://explorer.livepeer.org/orchestrators) sorts by Forecasted Yield by default; every column is sortable.

<DynamicTableV2
  headerList={['Metric', 'What it shows', 'Why it matters']}
  itemsList={[
{
  Metric: <Subtitle variant="changelog">**Orchestrator**</Subtitle>,
  'What it shows': 'Rank, ENS name or address. The account coordinating transcoders and AI workers and receiving fees and rewards.',
  'Why it matters': 'Identity for selection and citation. Rank is by Forecasted Yield by default, but the column header is sortable.',
},
{
  Metric: <Subtitle variant="changelog">**Delegated Stake**</Subtitle>,
  'What it shows': 'Total LPT bonded to this Orchestrator: own bond plus all Delegators. Subgraph field: `Transcoder.totalStake`.',
  'Why it matters': 'Determines active-set ranking and reward share. Larger stake means a larger share of inflation rewards each round.',
},
{
  Metric: <Subtitle variant="changelog">**Trailing 90D Fees**</Subtitle>,
  'What it shows': 'ETH redeemed by this Orchestrator in the last 90 calendar days. Subgraph field: `Transcoder.ninetyDayVolumeETH`.',
  'Why it matters': 'The Orchestrator\'s actual demand-side performance. A high value means Gateways are routing to this Orchestrator at scale.',
},
{
  Metric: <Subtitle variant="changelog">**Reward Cut**</Subtitle>,
  'What it shows': 'Percent of inflation rewards the Orchestrator keeps. The rest is distributed to Delegators by stake share. Subgraph field: `Transcoder.rewardCut` (PPM-million; divide by 10000 for percent).',
  'Why it matters': 'A higher Reward Cut means the Delegator receives less LPT inflation. Lower is better for the Delegator.',
},
{
  Metric: <Subtitle variant="changelog">**Fee Cut**</Subtitle>,
  'What it shows': 'Percent of ETH fees the Orchestrator keeps. Stored as `feeShare` (the inverse direction): Fee Cut = `1 − feeShare`. Subgraph field: `Transcoder.feeShare` (PPM-million).',
  'Why it matters': 'A higher Fee Cut means the Delegator receives less ETH from each job. Lower is better for the Delegator. Often confused with Reward Cut, but they apply to different income streams.',
},
{
  Metric: <Subtitle variant="changelog">**Reward Call Ratio (90d)**</Subtitle>,
  'What it shows': 'Percent of the last 90 rounds in which this Orchestrator successfully called `reward()`. Computed from the `pools` subgraph query, counting non-null `rewardTokens` over total rounds.',
  'Why it matters': 'A reliability signal. An Orchestrator that misses reward calls forfeits that round\'s LPT inflation for everyone bonded to them, including Delegators.',
},
{
  Metric: <Subtitle variant="changelog">**Latest Fee/Reward Change**</Subtitle>,
  'What it shows': 'Days since the Orchestrator last changed Reward Cut or Fee Cut. Computed from `feeShareUpdateTimestamp` and `rewardCutUpdateTimestamp`.',
  'Why it matters': 'A recent change may signal the Orchestrator is competing for delegation. A multi-year-stable rate means the operator is settled.',
},
{
  Metric: <Subtitle variant="changelog">**Treasury Cut (per pool)**</Subtitle>,
  'What it shows': 'Percent of each round\'s LPT inflation routed to the protocol treasury before any Orchestrator or Delegator allocation. On-chain: `BondingManager.treasuryRewardCutRate()`.',
  'Why it matters': 'Reduces real LPT yield to all stakers in proportion to the treasury cut. Currently set by governance.',
},
]}
/>

<CustomDivider style={{ margin: '-1rem 0 -2rem 0' }} />

## Gateway Columns

Gateway metrics are demand-side: who is routing jobs and paying fees. The Gateway list at [explorer.livepeer.org/Gateways](https://explorer.livepeer.org/gateways) shows every Gateway with a recent winning ticket redemption.

<DynamicTableV2
  headerList={['Metric', 'What it shows', 'Why it matters']}
  itemsList={[
{
  Metric: <Subtitle variant="changelog">**Gateway**</Subtitle>,
  'What it shows': 'Rank, ENS name or address. The account routing jobs to Orchestrators and paying fees.',
  'Why it matters': 'Identity for the demand side of the network. Major Gateways correspond to specific products built on Livepeer.',
},
{
  Metric: <Subtitle variant="changelog">**Deposit**</Subtitle>,
  'What it shows': 'Current ETH deposit balance funded for ticket redemptions. Subgraph field: `Broadcaster.deposit`.',
  'Why it matters': 'A funded deposit means the Gateway can pay for jobs. Drained deposits cause settlement failures and signal an inactive Gateway.',
},
{
  Metric: <Subtitle variant="changelog">**Reserve**</Subtitle>,
  'What it shows': 'Reserve ETH available for Orchestrators to claim if the deposit runs out mid-session. Subgraph field: `Broadcaster.reserve`.',
  'Why it matters': 'A backstop against deposit exhaustion. Per-Orchestrator reserve share is `reserve / activeTranscoderCount`.',
},
{
  Metric: <Subtitle variant="changelog">**90d Fees**</Subtitle>,
  'What it shows': 'ETH paid by this Gateway through winning ticket settlements in the last 90 days. Subgraph field: `Broadcaster.ninetyDayVolumeETH`.',
  'Why it matters': 'Recent demand contribution. The Gateway\'s share of 90d Fees Paid network-wide.',
},
{
  Metric: <Subtitle variant="changelog">**Total Fees**</Subtitle>,
  'What it shows': 'Lifetime ETH paid by this Gateway. Subgraph field: `Broadcaster.totalVolumeETH`.',
  'Why it matters': 'Cumulative Gateway impact on the network. Used for ranking and historical analysis.',
},
{
  Metric: <Subtitle variant="changelog">**Number of Active Gateways (computed)**</Subtitle>,
  'What it shows': 'Count of `Broadcaster` entities where `lastActiveDay` is within the last 30 days. Computed from the Gateways subgraph query.',
  'Why it matters': 'Demand-side decentralisation. A network served by many Gateways is more resilient than one dominated by a single integrator.',
},
{
  Metric: <Subtitle variant="changelog">**Top Gateway Concentration (computed)**</Subtitle>,
  'What it shows': 'Sum of top-10 Gateway 90d fees divided by network 90d fees. Computed from the same subgraph query.',
  'Why it matters': 'The dual of Top 10 Stake Concentration on the supply side. A high value signals demand-side concentration risk.',
},
]}
/>

<CustomDivider style={{ margin: '-1rem 0 -2rem 0' }} />

## Performance Leaderboard

A measurement service runs reference test jobs against every active Orchestrator from each measurement region. Scores aggregate the results. Transcoding and AI scores are tracked separately; AI is further split by pipeline (text-to-image, image-to-image, image-to-video, audio-to-text, text-to-speech, live-video-to-video) and model. The leaderboard sits at [explorer.livepeer.org/leaderboard](https://explorer.livepeer.org/leaderboard).

<DynamicTableV2
  headerList={['Metric', 'What it shows', 'Why it matters']}
  itemsList={[
{
  Metric: <Subtitle variant="changelog">**Total Score (0-10)**</Subtitle>,
  'What it shows': 'Composite score per region. Transcoding: combines Latency Score and Success Rate. AI: emphasises Success Rate over Latency Score.',
  'Why it matters': 'Single-number ranking for Orchestrator quality. The leaderboard sorts by this column by default.',
},
{
  Metric: <Subtitle variant="changelog">**Success Rate (%)**</Subtitle>,
  'What it shows': 'Percent of test jobs the Orchestrator successfully completed in the most recent measurement window for the selected region.',
  'Why it matters': 'Reliability metric. Failed jobs cost the Gateway nothing but signal that the Orchestrator cannot consistently deliver.',
},
{
  Metric: <Subtitle variant="changelog">**Latency Score (0-10)**</Subtitle>,
  'What it shows': 'Round-trip-time score. Transcoding: average test segment duration vs. round-trip time. AI: average round-trip time vs. the median across Orchestrators.',
  'Why it matters': 'Quality signal for time-sensitive work like live video transcoding and real-time AI.',
},
{
  Metric: <Subtitle variant="changelog">**Region**</Subtitle>,
  'What it shows': 'Geographic origin of the test job: GLOBAL, FRA (Frankfurt), LAX (Los Angeles), MDW (Chicago), NYC (New York), PRG (Prague), SIN (Singapore), SAO (São Paulo), LON (London). Specific list varies by pipeline type.',
  'Why it matters': 'Latency is region-dependent. An Orchestrator strong in Europe may be weak in Asia. Gateways select by region for latency-critical workloads.',
},
{
  Metric: <Subtitle variant="changelog">**Pipeline / Model**</Subtitle>,
  'What it shows': 'For AI: the specific pipeline (e.g. `text-to-image`) and model (e.g. `SDXL-Lightning`) the score is for.',
  'Why it matters': 'AI capability is per-model, not per-Orchestrator. An Orchestrator may run SDXL-Lightning at high score and not run live video-to-video at all.',
},
{
  Metric: <Subtitle variant="changelog">**Price Per Pixel**</Subtitle>,
  'What it shows': 'The Orchestrator\'s advertised price-per-pixel for transcoding work. Source: [`nyc.livepeer.com/orchestratorStats`](https://nyc.livepeer.com/orchestratorStats), joined into the leaderboard response.',
  'Why it matters': 'Cost side of the Gateway selection decision. Performance plus price is what determines real routing.',
},
]}
/>

<CustomDivider style={{ margin: '-1rem 0 -2rem 0' }} />

## Treasury and Governance

The Treasury holds LPT funded by a configurable share of each round's inflation. Treasury proposals authorise spending; polls vote on protocol parameter changes. Treasury state is at [explorer.livepeer.org/treasury](https://explorer.livepeer.org/treasury).

<DynamicTableV2
  headerList={['Metric', 'What it shows', 'Why it matters']}
  itemsList={[
{
  Metric: <Subtitle variant="changelog">**Treasury Balance**</Subtitle>,
  'What it shows': 'LPT held by the Treasury contract. On-chain: `LivepeerToken.balanceOf(treasury)`. Treasury contract address is resolved via the Controller.',
  'Why it matters': 'Protocol-owned LPT available for governance-approved spending. The standing balance.',
},
{
  Metric: <Subtitle variant="changelog">**Treasury Reward Cut Rate**</Subtitle>,
  'What it shows': 'Percent of each round\'s minted LPT routed to the treasury. On-chain: `BondingManager.treasuryRewardCutRate()`. Currently set by governance {/* REVIEW: confirm current value pre-merge */}.',
  'Why it matters': 'The inflation tap. A higher rate funds the treasury faster but reduces real LPT yield to stakers.',
},
{
  Metric: <Subtitle variant="changelog">**Treasury Balance Ceiling**</Subtitle>,
  'What it shows': 'LPT balance cap. When the treasury reaches this value, `treasuryRewardCutRate` is treated as 0% until the balance falls below the ceiling. On-chain: `BondingManager.treasuryBalanceCeiling()` {/* REVIEW: confirm current value pre-merge */}.',
  'Why it matters': 'Self-limiting mechanism. The treasury cannot grow unbounded; once the ceiling is hit, the treasury cut goes to zero until the balance falls below it.',
},
{
  Metric: <Subtitle variant="changelog">**Treasury Inflows (annualised, computed)**</Subtitle>,
  'What it shows': '`inflation × treasuryRewardCutRate × annual rounds × Total Supply`. The LPT routed to treasury per year at current parameters.',
  'Why it matters': 'How fast the treasury fills. Compared with the ceiling, predicts when the treasury cut goes to zero.',
},
{
  Metric: <Subtitle variant="changelog">**Treasury Spend (lifetime, computed)**</Subtitle>,
  'What it shows': 'Sum of LPT spent via executed treasury proposals. Computed from the `TreasuryProposal` subgraph entity.',
  'Why it matters': 'How much the protocol has spent on funded initiatives (SPEs, RFPs, security work).',
},
{
  Metric: <Subtitle variant="changelog">**Treasury Proposals**</Subtitle>,
  'What it shows': 'Per-proposal: proposer, description, calldata, vote totals, state (Pending, Active, Succeeded, Defeated, Executed). Subgraph entity: `TreasuryProposal`.',
  'Why it matters': 'The list of decisions on protocol-owned funds. Each proposal links to its full vote history.',
},
{
  Metric: <Subtitle variant="changelog">**Polls**</Subtitle>,
  'What it shows': 'On-chain polls that vote on parameter change LIPs. Each poll has a creator, end block, and quorum threshold.',
  'Why it matters': 'How LIPs become protocol parameter changes. A poll that fails quorum cannot enact the change even if "Yes" outpolls "No".',
},
{
  Metric: <Subtitle variant="changelog">**Voter Turnout**</Subtitle>,
  'What it shows': 'Percent of `totalActiveStake` that voted on a given poll or proposal. Stake-weighted.',
  'Why it matters': 'Governance engagement signal. Low turnout on a proposal that nominally passes weakens its mandate.',
},
{
  Metric: <Subtitle variant="changelog">**Active Set Cap**</Subtitle>,
  'What it shows': 'Maximum Orchestrators eligible per round: `numActiveTranscoders`. On-chain: `BondingManager.numActiveTranscoders()`. Currently 100 {/* REVIEW: confirm cap pre-merge */}.',
  'Why it matters': 'Hard ceiling on how many independent Orchestrators can earn from the Active Set in any given round.',
},
]}
/>

For treasury balance over time, see Doug Petkanics's [Livepeer Treasury dashboard](https://dune.com/dob/livepeer-treasury) on Dune. Authoritative on-chain state is at [explorer.livepeer.org/treasury](https://explorer.livepeer.org/treasury).

<CustomDivider style={{ margin: '-1rem 0 -2rem 0' }} />

## Transactions Feed

A chronological feed of every state-changing protocol call sits at [explorer.livepeer.org/transactions](https://explorer.livepeer.org/transactions). Event types:

* **`BondEvent`**: a Delegator bonded LPT to an Orchestrator. Includes new Delegators, additional bonds, and switches from one delegate to another.
* **`UnbondEvent` / `RebondEvent`**: a Delegator started unbonding or rebonded before withdrawing.
* **`RewardEvent`**: an Orchestrator called `reward()` for a round and minted that round's share of LPT inflation.
* **`WinningTicketRedeemedEvent`**: a winning probabilistic ticket was settled on-chain, transferring ETH from Gateway to Orchestrator.
* **`DepositFundedEvent` / `ReserveFundedEvent`**: a Gateway funded its deposit or reserve.
* **`TranscoderActivatedEvent` / `TranscoderDeactivatedEvent`**: an Orchestrator entered or left the Active Set.
* **`TranscoderUpdateEvent`**: an Orchestrator changed `rewardCut`, `feeShare`, or service URI.

Every event is queryable from the subgraph and links through to the underlying Arbiscan transaction.

<CustomDivider style={{ margin: '-1rem 0 -2rem 0' }} />

## Endpoints

For analysts and researchers building dashboards or running scripts, the canonical endpoints in one block:

<BorderedBox variant="accent">
  <Subtitle style={{ fontSize: '1rem', marginBottom: '0.5rem' }}>**Explorer (live, authoritative for current state)**</Subtitle>

  Homepage: `https://explorer.livepeer.org/`
  Orchestrators: `https://explorer.livepeer.org/orchestrators`
  Gateways: `https://explorer.livepeer.org/gateways`
  Performance leaderboard: `https://explorer.livepeer.org/leaderboard`
  Treasury: `https://explorer.livepeer.org/treasury`
  Voting: `https://explorer.livepeer.org/voting`
  Transactions: `https://explorer.livepeer.org/transactions`
  Per-account: `https://explorer.livepeer.org/accounts/<address>/orchestrating`

  <Subtitle style={{ fontSize: '1rem', marginTop: '1rem', marginBottom: '0.5rem' }}>**Subgraph (Arbitrum One, every metric the Explorer reads)**</Subtitle>

  GraphQL: `https://gateway.thegraph.com/api/{API_KEY}/subgraphs/id/FE63YgkzcpVocxdCEyEYbvjYqEf2kb1A6daMYRxmejYC`

  Default deployment ID is configurable; the value above is the public default referenced in `livepeer/explorer/lib/chains.ts`.

  <Subtitle style={{ fontSize: '1rem', marginTop: '1rem', marginBottom: '0.5rem' }}>**Performance leaderboard API**</Subtitle>

  Aggregated transcoding stats: `https://leaderboard-serverless.vercel.app/api/aggregated_stats`
  Per-Orchestrator: `https://leaderboard-serverless.vercel.app/api/raw_stats?orchestrator=<address>`
  AI aggregated stats: `<AI_METRICS_SERVER_URL>/api/aggregated_stats?pipeline=<id>&model=<name>`
  Available pipelines: `<AI_METRICS_SERVER_URL>/api/pipelines?region=<region>`

  <Subtitle style={{ fontSize: '1rem', marginTop: '1rem', marginBottom: '0.5rem' }}>**Pricing (Orchestrator-advertised prices)**</Subtitle>

  All Orchestrators: `https://nyc.livepeer.com/orchestratorStats`

  <Subtitle style={{ fontSize: '1rem', marginTop: '1rem', marginBottom: '0.5rem' }}>**Dune dashboards**</Subtitle>

  Main: [`dune.com/ff3314/livepeer`](https://dune.com/ff3314/livepeer)
  AI: [`dune.com/rickstaa/livepeer-ai`](https://dune.com/rickstaa/livepeer-ai)
  Treasury: [`dune.com/dob/livepeer-treasury`](https://dune.com/dob/livepeer-treasury)
  Profitability: [`dune.com/Lizzl/livepeer-profitability-dashboard`](https://dune.com/Lizzl/livepeer-profitability-dashboard)
  Specific queries: [`4073378`](https://dune.com/queries/4073378) (transcoding fees, weekly), [`3983737`](https://dune.com/queries/3983737) (AI fees, weekly)

  <Subtitle style={{ fontSize: '1rem', marginTop: '1rem', marginBottom: '0.5rem' }}>**On-chain contracts (Arbitrum One)**</Subtitle>

  Controller: `0xD8E8328501E9645d16Cf49539efC04f734606ee4`
  PollCreator: `0x8bb50806D60c492c0004DAD5D9627DAA2d9732E6`
  Other contracts (BondingManager, TicketBroker, ServiceRegistry, Minter, Treasury, LivepeerGovernor) are resolved via the Controller. See [Blockchain Contracts](/v2/about/protocol/blockchain-contracts).
</BorderedBox>

<CustomDivider />

## Related Pages

<Columns cols={2}>
  <Card title={<CustomCardTitle icon="chart-line" title="Network Observability" />} href="/v2/about/network/observability" horizontal arrow>
    The five surfaces these metrics come from, end-to-end.
  </Card>

  <Card title={<CustomCardTitle icon="diagram-project" title="Network Architecture" />} href="/v2/about/network/architecture" horizontal arrow>
    The Network topology that produces every metric on this page.
  </Card>

  <Card title={<CustomCardTitle icon="store" title="Marketplace Model" />} href="/v2/about/network/marketplace-model" horizontal arrow>
    What fee volume, settlement, and ticket redemption represent.
  </Card>

  <Card title={<CustomCardTitle icon="file-code" title="Blockchain Contracts" />} href="/v2/about/protocol/blockchain-contracts" horizontal arrow>
    Contract addresses backing every on-chain metric on this page.
  </Card>
</Columns>
