Skip to content

Conversation

@rickstaa
Copy link
Member

@rickstaa rickstaa commented Nov 22, 2025

This pull request introduces new gateway widgets and pages to display stats for active gateways that have distributed fees in the last 90 days. Adds a gateways widget to the main page, a dedicated gateway tab, and a gateway account page for detailed gateway stats and activity.

Warning

Needs upstream pull request livepeer/subgraph#168 to be merged and deployed for this to work!
Please remove the patch in codegen.yaml before merging.=!

@rickstaa rickstaa requested a review from ECWireless as a code owner November 22, 2025 12:19
@vercel
Copy link

vercel bot commented Nov 22, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
explorer-arbitrum-one Ready Ready Preview, Comment Jan 9, 2026 2:55pm

Introduce new gateway widgets and pages to display stats for active
gateways that have distributed fees in the last 90 days. Adds a gateways widget to
the main page, a dedicated gateway tab, and a gateway account page for detailed
gateway stats and activity.
Ensure that paid tickets also show up on the GatewayHistory.
Ensure the orchestrators button has the right background when the
`/orchestrators` page is selected and the user is logged out.
@rickstaa rickstaa force-pushed the feat/add-gateway-dashboard branch from 3a6d1a3 to 3adb176 Compare December 28, 2025 10:31
Ensure that the gateways tab is highlighted when on a gateway profile
and the orchestrator tab when on a orchestrator profile.
Ensure we include gateways that were activated in the last year or did
send tickets in the last 90D. Also improve the UI to make this behavoir
more visible.
Ensure gateway tab is shown before the delegator tab if an entity is
both a orchestrator and gateway.
@rickstaa
Copy link
Member Author

rickstaa commented Dec 29, 2025

@ECWireless, when you have time, could you review this after livepeer/subgraph#168 is merged and deployed upstream? This would be a great feature for the community. Please check the warning section above before merging.

You can merge #469 and #468 first and then rebase.

rickstaa and others added 4 commits December 30, 2025 12:34
Make scrollbuffer a constant to improve code readability.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com
Ensure that the container scrolls to the active page when clicked.
Recalculate overflow effects when child elements change to ensure consistent
fading.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Fixes a bug in the gateway filtering which caused it to not adhere to
our filtering condition. Also applied some small code improvements.
@rickstaa rickstaa marked this pull request as ready for review January 9, 2026 14:52
Copilot AI review requested due to automatic review settings January 9, 2026 14:52
const currentTimestamp = Math.floor(Date.now() / 1000);
const minActiveDay = Math.max(currentTimestamp - 365 * 86400, 0); // include activated last 12 months

// TODO: paginate gateways; currently under the 1000 entity cap.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ECWireless this is ready for your teams review. Keep in mind I did not implement pagination since we have less than 100 gateways right now and the maximum entitry cap is 1000. You can decide if you want to be proactive and already add pagniation or create an issue to tackle it later. Thanks. 🙏🏻

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request adds comprehensive gateway (broadcaster) statistics and management features to the Livepeer Explorer. The implementation introduces new pages, components, and queries to display gateway activity, including fees distributed, deposit/reserve balances, and self-redemption detection.

Key changes:

  • New gateway list page and component with sortable statistics
  • Gateway account page with broadcasting stats and self-redeem indicator
  • Enhanced transaction history to distinguish between incoming, outgoing, and self-redeemed winning tickets
  • Navigation updates to include gateway-specific routes and tabs

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
queries/transactions.graphql Added sender/recipient fields to WinningTicketRedeemedEvent for directional tracking
queries/gateways.graphql New query to fetch active gateways with volume and activity metrics
queries/gatewaySelfRedeem.graphql Query to detect self-redemption behavior for gateways
queries/account.graphql Added gateway (broadcaster) data to account queries
pages/index.tsx Integrated gateway list widget on home page with top 10 gateways
pages/gateways.tsx New dedicated page listing all active gateways
pages/accounts/[account]/broadcasting.tsx New broadcasting tab for gateway account pages
lib/api/ssr.ts Added getGateways function to fetch gateway data server-side
layouts/main.tsx Added gateway navigation item and highlight logic
layouts/account.tsx Added broadcasting tab and conditional display logic
hooks/useGatewaySelfRedeemStatus.ts Hook to detect self-redemption within a time window
hooks/index.tsx Exported new gateway hook
components/HistoryView/index.tsx Enhanced to show directional indicators for winning tickets
components/GatewayList/index.tsx New table component displaying gateway statistics
components/BroadcastingView/index.tsx Gateway stats view with self-redeem warnings
apollo/subgraph.ts Generated TypeScript types for new gateway-related fields

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +12 to +18
const formatEth = (value?: string | number | null) => {
const amount = Number(value ?? 0) || 0;
return `${numbro(amount).format(
amount > 0 && amount < 0.01
? { mantissa: 4, trimMantissa: true }
: { mantissa: 2, average: true, lowPrecision: false }
)} ETH`;
Copy link

Copilot AI Jan 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code duplication: The formatEth function is duplicated in both BroadcastingView and GatewayList components with identical implementation. The TODOs in both files acknowledge this should be replaced with a common formatting utility. Consider extracting this to a shared utility module to follow DRY principles and ensure consistent formatting across the application.

Suggested change
const formatEth = (value?: string | number | null) => {
const amount = Number(value ?? 0) || 0;
return `${numbro(amount).format(
amount > 0 && amount < 0.01
? { mantissa: 4, trimMantissa: true }
: { mantissa: 2, average: true, lowPrecision: false }
)} ETH`;
const SMALL_ETH_FORMAT = { mantissa: 4, trimMantissa: true } as const;
const DEFAULT_ETH_FORMAT = {
mantissa: 2,
average: true,
lowPrecision: false,
} as const;
const formatEth = (value?: string | number | null) => {
const raw = value == null ? 0 : Number(value);
const amount = Number.isFinite(raw) && !Number.isNaN(raw) ? raw : 0;
const formatOptions =
amount > 0 && amount < 0.01 ? SMALL_ETH_FORMAT : DEFAULT_ETH_FORMAT;
return `${numbro(amount).format(formatOptions)} ETH`;

Copilot uses AI. Check for mistakes.
<Head>
<title>Livepeer Explorer - Gateways</title>
</Head>
<Container css={{ maxWidth: "", width: "100%" }}>
Copy link

Copilot AI Jan 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty maxWidth value in Container CSS. Setting maxWidth to an empty string is unusual and likely unintentional. This should either be removed (to use the default) or set to a specific value. Review whether this matches the intended design specification.

Suggested change
<Container css={{ maxWidth: "", width: "100%" }}>
<Container css={{ width: "100%" }}>

Copilot uses AI. Check for mistakes.
Comment on lines +65 to +76
return tickets
.filter((e) => (e?.transaction?.timestamp ?? 0) > lastEventTimestamp)
.map((e) => ({
...e,
direction:
e?.sender?.id?.toLowerCase() === accountLower &&
e?.recipient?.id?.toLowerCase() === accountLower
? ("self" as const)
: e?.sender?.id?.toLowerCase() === accountLower
? ("out" as const)
: ("in" as const),
}));
Copy link

Copilot AI Jan 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicate filtering in ticketEvents computation. The tickets are filtered twice with the same condition (timestamp > lastEventTimestamp) - once when creating the tickets array and again in the subsequent filter operation. Remove the redundant second filter.

Suggested change
return tickets
.filter((e) => (e?.transaction?.timestamp ?? 0) > lastEventTimestamp)
.map((e) => ({
...e,
direction:
e?.sender?.id?.toLowerCase() === accountLower &&
e?.recipient?.id?.toLowerCase() === accountLower
? ("self" as const)
: e?.sender?.id?.toLowerCase() === accountLower
? ("out" as const)
: ("in" as const),
}));
return tickets.map((e) => ({
...e,
direction:
e?.sender?.id?.toLowerCase() === accountLower &&
e?.recipient?.id?.toLowerCase() === accountLower
? ("self" as const)
: e?.sender?.id?.toLowerCase() === accountLower
? ("out" as const)
: ("in" as const),
}));

Copilot uses AI. Check for mistakes.
Comment on lines +36 to +40
return `${numbro(amount).format(
amount > 0 && amount < 0.01
? { mantissa: 4, trimMantissa: true }
: { mantissa: 2, average: true, lowPrecision: false }
)} ETH`;
Copy link

Copilot AI Jan 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code duplication: The formatEth function is duplicated in both GatewayList and BroadcastingView components with identical implementation. The TODOs in both files acknowledge this should be replaced with a common formatting utility. Consider extracting this to a shared utility module to follow DRY principles and ensure consistent formatting across the application.

Suggested change
return `${numbro(amount).format(
amount > 0 && amount < 0.01
? { mantissa: 4, trimMantissa: true }
: { mantissa: 2, average: true, lowPrecision: false }
)} ETH`;
const formatOptions =
amount > 0 && amount < 0.01
? { mantissa: 4, trimMantissa: true }
: { mantissa: 2, average: true, lowPrecision: false };
return `${numbro(amount).format(formatOptions)} ETH`;

Copilot uses AI. Check for mistakes.
Comment on lines +276 to +278
onPointerEnterCapture={undefined}
onPointerLeaveCapture={undefined}
placeholder={undefined}
Copy link

Copilot AI Jan 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary properties passed to PopoverContent. The properties onPointerEnterCapture, onPointerLeaveCapture, and placeholder are set to undefined, which serves no functional purpose. These should be removed unless they are required for TypeScript compatibility reasons (in which case this indicates a type definition issue that should be addressed).

Suggested change
onPointerEnterCapture={undefined}
onPointerLeaveCapture={undefined}
placeholder={undefined}

Copilot uses AI. Check for mistakes.
const { orchestrators } = await getOrchestrators(client);
const { events } = await getEvents(client);
const protocol = await getProtocol(client);
const { gateways } = await getGateways();
Copy link

Copilot AI Jan 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent Apollo client usage. The getGateways function is called without passing the client parameter, which means it creates its own Apollo client instance via getApollo(). Meanwhile, getOrchestrators and getProtocol are explicitly passed the client. This inconsistency could lead to multiple client instances and potential caching issues. Pass the client to getGateways for consistency.

Suggested change
const { gateways } = await getGateways();
const { gateways } = await getGateways(client);

Copilot uses AI. Check for mistakes.
Profile
</PopoverLink>
<PopoverLink
href={`/accounts/${row.values.id}/broadcasting?tab=history`}
Copy link

Copilot AI Jan 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Invalid query parameter for navigation. The link uses ?tab=history but the routing system doesn't appear to handle a 'tab' query parameter. The account pages use path-based routing (e.g., /accounts/{address}/history) rather than query-based navigation. This link should be /accounts/${row.values.id}/history instead.

Suggested change
href={`/accounts/${row.values.id}/broadcasting?tab=history`}
href={`/accounts/${row.values.id}/history`}

Copilot uses AI. Check for mistakes.
@rickstaa
Copy link
Member Author

rickstaa commented Jan 9, 2026

@ECWireless can your team handle the co-pilot comments as I'm out of office thanks. 🙏🏻

Also keep in mind that its best to wait till the subgraph is fully indexed before merging this. You can see the status of v1.3.0 here.

image

@rickstaa
Copy link
Member Author

rickstaa commented Jan 9, 2026

@ECWireless something seems to be wrong with https://explorer-arbitrum-one-git-feat-add-g-10dba1-livepeer-foundation.vercel.app/accounts/0x173173b30b5d3c8f09ee78816da8a6402d6b16e1/broadcasting for the 90d fees will have to check subgraph logic which does return 0 while total and the days data is correct.

@rickstaa
Copy link
Member Author

rickstaa commented Jan 9, 2026

@ECWireless something seems to be wrong with https://explorer-arbitrum-one-git-feat-add-g-10dba1-livepeer-foundation.vercel.app/accounts/0x173173b30b5d3c8f09ee78816da8a6402d6b16e1/broadcasting for the 90d fees will have to check subgraph logic which does return 0 while total and the days data is correct.

Found the issue will create path tomorrow.

@rickstaa
Copy link
Member Author

rickstaa commented Jan 10, 2026

@ECWireless created a fix on the subgraph here. Will wait for it to fully sync test it, ask for review and then publish v1.3.1. After that is done you can review and merge when you seem fit.

@rickstaa
Copy link
Member Author

rickstaa commented Jan 13, 2026

Hey @mehrdadmms, I fixed the upstream data inaccuracy in livepeer/subgraph#202. It’s currently syncing in the CI deployment on the Graph Studio portal.

I’m now fully out of office and won’t be able to support moving this forward. This PR is not a deliverable for the Transformation spec, so there’s no urgency.

If you’d like to proceed before I’m back, please ask BuildersDAO to review the PR, then have Yondon or yourself verify the deployment in Studio, and finally merge and tag a new release.

@rickstaa rickstaa marked this pull request as draft January 13, 2026 20:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants