-
Notifications
You must be signed in to change notification settings - Fork 17
feat(gateways): add gateway stats widgets and new gateway pages #410
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
1130056 to
f0795f7
Compare
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.
5e54fca to
50655d3
Compare
3a6d1a3 to
3adb176
Compare
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.
|
@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. |
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>
de99f84 to
bbc039e
Compare
Fixes a bug in the gateway filtering which caused it to not adhere to our filtering condition. Also applied some small code improvements.
| 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. |
There was a problem hiding this comment.
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. 🙏🏻
There was a problem hiding this 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.
| 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`; |
Copilot
AI
Jan 9, 2026
There was a problem hiding this comment.
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.
| 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`; |
| <Head> | ||
| <title>Livepeer Explorer - Gateways</title> | ||
| </Head> | ||
| <Container css={{ maxWidth: "", width: "100%" }}> |
Copilot
AI
Jan 9, 2026
There was a problem hiding this comment.
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.
| <Container css={{ maxWidth: "", width: "100%" }}> | |
| <Container css={{ width: "100%" }}> |
| 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), | ||
| })); |
Copilot
AI
Jan 9, 2026
There was a problem hiding this comment.
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.
| 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), | |
| })); |
| return `${numbro(amount).format( | ||
| amount > 0 && amount < 0.01 | ||
| ? { mantissa: 4, trimMantissa: true } | ||
| : { mantissa: 2, average: true, lowPrecision: false } | ||
| )} ETH`; |
Copilot
AI
Jan 9, 2026
There was a problem hiding this comment.
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.
| 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`; |
| onPointerEnterCapture={undefined} | ||
| onPointerLeaveCapture={undefined} | ||
| placeholder={undefined} |
Copilot
AI
Jan 9, 2026
There was a problem hiding this comment.
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).
| onPointerEnterCapture={undefined} | |
| onPointerLeaveCapture={undefined} | |
| placeholder={undefined} |
| const { orchestrators } = await getOrchestrators(client); | ||
| const { events } = await getEvents(client); | ||
| const protocol = await getProtocol(client); | ||
| const { gateways } = await getGateways(); |
Copilot
AI
Jan 9, 2026
There was a problem hiding this comment.
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.
| const { gateways } = await getGateways(); | |
| const { gateways } = await getGateways(client); |
| Profile | ||
| </PopoverLink> | ||
| <PopoverLink | ||
| href={`/accounts/${row.values.id}/broadcasting?tab=history`} |
Copilot
AI
Jan 9, 2026
There was a problem hiding this comment.
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.
| href={`/accounts/${row.values.id}/broadcasting?tab=history`} | |
| href={`/accounts/${row.values.id}/history`} |
|
@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.
|
|
@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. |
|
@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. |
|
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. |

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.=!