Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 27 additions & 28 deletions apollo/subgraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9655,15 +9655,12 @@ export type TransactionsQueryVariables = Exact<{

export type TransactionsQuery = { __typename: 'Query', transactions: Array<{ __typename: 'Transaction', events?: Array<{ __typename: 'BondEvent', additionalAmount: string, delegator: { __typename: 'Delegator', id: string }, newDelegate: { __typename: 'Transcoder', id: string }, oldDelegate?: { __typename: 'Transcoder', id: string } | null, round: { __typename: 'Round', id: string }, transaction: { __typename: 'Transaction', id: string, timestamp: number } } | { __typename: 'BurnEvent', round: { __typename: 'Round', id: string }, transaction: { __typename: 'Transaction', id: string, timestamp: number } } | { __typename: 'DepositFundedEvent', amount: string, sender: { __typename: 'Broadcaster', id: string }, round: { __typename: 'Round', id: string }, transaction: { __typename: 'Transaction', id: string, timestamp: number } } | { __typename: 'EarningsClaimedEvent', round: { __typename: 'Round', id: string }, transaction: { __typename: 'Transaction', id: string, timestamp: number } } | { __typename: 'MigrateDelegatorFinalizedEvent', round: { __typename: 'Round', id: string }, transaction: { __typename: 'Transaction', id: string, timestamp: number } } | { __typename: 'MintEvent', round: { __typename: 'Round', id: string }, transaction: { __typename: 'Transaction', id: string, timestamp: number } } | { __typename: 'NewRoundEvent', round: { __typename: 'Round', id: string }, transaction: { __typename: 'Transaction', id: string, timestamp: number } } | { __typename: 'ParameterUpdateEvent', round: { __typename: 'Round', id: string }, transaction: { __typename: 'Transaction', id: string, timestamp: number } } | { __typename: 'PauseEvent', round: { __typename: 'Round', id: string }, transaction: { __typename: 'Transaction', id: string, timestamp: number } } | { __typename: 'PollCreatedEvent', round: { __typename: 'Round', id: string }, transaction: { __typename: 'Transaction', id: string, timestamp: number } } | { __typename: 'RebondEvent', amount: string, delegate: { __typename: 'Transcoder', id: string }, round: { __typename: 'Round', id: string }, transaction: { __typename: 'Transaction', id: string, timestamp: number } } | { __typename: 'ReserveClaimedEvent', round: { __typename: 'Round', id: string }, transaction: { __typename: 'Transaction', id: string, timestamp: number } } | { __typename: 'ReserveFundedEvent', amount: string, reserveHolder: { __typename: 'Broadcaster', id: string }, round: { __typename: 'Round', id: string }, transaction: { __typename: 'Transaction', id: string, timestamp: number } } | { __typename: 'RewardEvent', rewardTokens: string, round: { __typename: 'Round', id: string }, transaction: { __typename: 'Transaction', id: string, timestamp: number } } | { __typename: 'ServiceURIUpdateEvent', round: { __typename: 'Round', id: string }, transaction: { __typename: 'Transaction', id: string, timestamp: number } } | { __typename: 'SetCurrentRewardTokensEvent', round: { __typename: 'Round', id: string }, transaction: { __typename: 'Transaction', id: string, timestamp: number } } | { __typename: 'StakeClaimedEvent', round: { __typename: 'Round', id: string }, transaction: { __typename: 'Transaction', id: string, timestamp: number } } | { __typename: 'TranscoderActivatedEvent', round: { __typename: 'Round', id: string }, transaction: { __typename: 'Transaction', id: string, timestamp: number } } | { __typename: 'TranscoderDeactivatedEvent', round: { __typename: 'Round', id: string }, transaction: { __typename: 'Transaction', id: string, timestamp: number } } | { __typename: 'TranscoderEvictedEvent', round: { __typename: 'Round', id: string }, transaction: { __typename: 'Transaction', id: string, timestamp: number } } | { __typename: 'TranscoderResignedEvent', round: { __typename: 'Round', id: string }, transaction: { __typename: 'Transaction', id: string, timestamp: number } } | { __typename: 'TranscoderSlashedEvent', round: { __typename: 'Round', id: string }, transaction: { __typename: 'Transaction', id: string, timestamp: number } } | { __typename: 'TranscoderUpdateEvent', rewardCut: string, feeShare: string, round: { __typename: 'Round', id: string }, transaction: { __typename: 'Transaction', id: string, timestamp: number } } | { __typename: 'TransferBondEvent', round: { __typename: 'Round', id: string }, transaction: { __typename: 'Transaction', id: string, timestamp: number } } | { __typename: 'TreasuryVoteEvent', id: string, reason?: string | null, support: TreasuryVoteSupport, timestamp: number, weight: string, proposal: { __typename: 'TreasuryProposal', id: string, targets: Array<string>, description: string }, treasuryVoter: { __typename: 'LivepeerAccount', id: string }, round: { __typename: 'Round', id: string }, transaction: { __typename: 'Transaction', id: string, timestamp: number } } | { __typename: 'UnbondEvent', amount: string, delegate: { __typename: 'Transcoder', id: string }, round: { __typename: 'Round', id: string }, transaction: { __typename: 'Transaction', id: string, timestamp: number } } | { __typename: 'UnpauseEvent', round: { __typename: 'Round', id: string }, transaction: { __typename: 'Transaction', id: string, timestamp: number } } | { __typename: 'VoteEvent', voter: string, choiceID: string, id: string, timestamp: number, poll: { __typename: 'Poll', id: string, proposal: string, endBlock: string, quorum: string, quota: string }, transaction: { __typename: 'Transaction', id: string, timestamp: number }, round: { __typename: 'Round', id: string } } | { __typename: 'WinningTicketRedeemedEvent', faceValue: string, round: { __typename: 'Round', id: string }, transaction: { __typename: 'Transaction', id: string, timestamp: number } } | { __typename: 'WithdrawFeesEvent', amount: string, round: { __typename: 'Round', id: string }, transaction: { __typename: 'Transaction', id: string, timestamp: number } } | { __typename: 'WithdrawStakeEvent', amount: string, round: { __typename: 'Round', id: string }, transaction: { __typename: 'Transaction', id: string, timestamp: number } } | { __typename: 'WithdrawalEvent', round: { __typename: 'Round', id: string }, transaction: { __typename: 'Transaction', id: string, timestamp: number } }> | null }>, winningTicketRedeemedEvents: Array<{ __typename: 'WinningTicketRedeemedEvent', id: string, faceValue: string, round: { __typename: 'Round', id: string }, transaction: { __typename: 'Transaction', id: string, timestamp: number } }> };

export type TranscoderActivatedEventsQueryVariables = Exact<{
where?: InputMaybe<TranscoderActivatedEvent_Filter>;
first?: InputMaybe<Scalars['Int']>;
orderBy?: InputMaybe<TranscoderActivatedEvent_OrderBy>;
orderDirection?: InputMaybe<OrderDirection>;
export type TranscoderActivationHistoryQueryVariables = Exact<{
delegate: Scalars['String'];
}>;


export type TranscoderActivatedEventsQuery = { __typename: 'Query', transcoderActivatedEvents: Array<{ __typename: 'TranscoderActivatedEvent', activationRound: string, id: string }> };
export type TranscoderActivationHistoryQuery = { __typename: 'Query', transcoderActivatedEvents: Array<{ __typename: 'TranscoderActivatedEvent', activationRound: string }>, transcoderDeactivatedEvents: Array<{ __typename: 'TranscoderDeactivatedEvent', deactivationRound: string }> };

export type TreasuryProposalQueryVariables = Exact<{
id: Scalars['ID'];
Expand Down Expand Up @@ -10637,50 +10634,52 @@ export function useTransactionsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptio
export type TransactionsQueryHookResult = ReturnType<typeof useTransactionsQuery>;
export type TransactionsLazyQueryHookResult = ReturnType<typeof useTransactionsLazyQuery>;
export type TransactionsQueryResult = Apollo.QueryResult<TransactionsQuery, TransactionsQueryVariables>;
export const TranscoderActivatedEventsDocument = gql`
query transcoderActivatedEvents($where: TranscoderActivatedEvent_filter, $first: Int, $orderBy: TranscoderActivatedEvent_orderBy, $orderDirection: OrderDirection) {
export const TranscoderActivationHistoryDocument = gql`
query transcoderActivationHistory($delegate: String!) {
transcoderActivatedEvents(
where: $where
first: $first
orderBy: $orderBy
orderDirection: $orderDirection
where: {delegate: $delegate}
orderBy: activationRound
orderDirection: asc
) {
activationRound
id
}
transcoderDeactivatedEvents(
where: {delegate: $delegate}
orderBy: deactivationRound
orderDirection: asc
) {
deactivationRound
}
}
`;

/**
* __useTranscoderActivatedEventsQuery__
* __useTranscoderActivationHistoryQuery__
*
* To run a query within a React component, call `useTranscoderActivatedEventsQuery` and pass it any options that fit your needs.
* When your component renders, `useTranscoderActivatedEventsQuery` returns an object from Apollo Client that contains loading, error, and data properties
* To run a query within a React component, call `useTranscoderActivationHistoryQuery` and pass it any options that fit your needs.
* When your component renders, `useTranscoderActivationHistoryQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useTranscoderActivatedEventsQuery({
* const { data, loading, error } = useTranscoderActivationHistoryQuery({
* variables: {
* where: // value for 'where'
* first: // value for 'first'
* orderBy: // value for 'orderBy'
* orderDirection: // value for 'orderDirection'
* delegate: // value for 'delegate'
* },
* });
*/
export function useTranscoderActivatedEventsQuery(baseOptions?: Apollo.QueryHookOptions<TranscoderActivatedEventsQuery, TranscoderActivatedEventsQueryVariables>) {
export function useTranscoderActivationHistoryQuery(baseOptions: Apollo.QueryHookOptions<TranscoderActivationHistoryQuery, TranscoderActivationHistoryQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<TranscoderActivatedEventsQuery, TranscoderActivatedEventsQueryVariables>(TranscoderActivatedEventsDocument, options);
return Apollo.useQuery<TranscoderActivationHistoryQuery, TranscoderActivationHistoryQueryVariables>(TranscoderActivationHistoryDocument, options);
}
export function useTranscoderActivatedEventsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<TranscoderActivatedEventsQuery, TranscoderActivatedEventsQueryVariables>) {
export function useTranscoderActivationHistoryLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<TranscoderActivationHistoryQuery, TranscoderActivationHistoryQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<TranscoderActivatedEventsQuery, TranscoderActivatedEventsQueryVariables>(TranscoderActivatedEventsDocument, options);
return Apollo.useLazyQuery<TranscoderActivationHistoryQuery, TranscoderActivationHistoryQueryVariables>(TranscoderActivationHistoryDocument, options);
}
export type TranscoderActivatedEventsQueryHookResult = ReturnType<typeof useTranscoderActivatedEventsQuery>;
export type TranscoderActivatedEventsLazyQueryHookResult = ReturnType<typeof useTranscoderActivatedEventsLazyQuery>;
export type TranscoderActivatedEventsQueryResult = Apollo.QueryResult<TranscoderActivatedEventsQuery, TranscoderActivatedEventsQueryVariables>;
export type TranscoderActivationHistoryQueryHookResult = ReturnType<typeof useTranscoderActivationHistoryQuery>;
export type TranscoderActivationHistoryLazyQueryHookResult = ReturnType<typeof useTranscoderActivationHistoryLazyQuery>;
export type TranscoderActivationHistoryQueryResult = Apollo.QueryResult<TranscoderActivationHistoryQuery, TranscoderActivationHistoryQueryVariables>;
export const TreasuryProposalDocument = gql`
query treasuryProposal($id: ID!) {
treasuryProposal(id: $id) {
Expand Down
167 changes: 120 additions & 47 deletions components/OrchestratingView/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ import { Box, Flex, Link as A, Text } from "@livepeer/design-system";
import { ArrowTopRightIcon, CheckIcon, Cross1Icon } from "@modulz/radix-icons";
import {
AccountQueryResult,
OrderDirection,
TranscoderActivatedEvent_OrderBy,
useTranscoderActivatedEventsQuery,
useTranscoderActivationHistoryQuery,
useTreasuryProposalsQuery,
useTreasuryVotesQuery,
} from "apollo";
Expand All @@ -32,56 +30,128 @@ interface Props {
isActive: boolean;
}

const Index = ({ currentRound, transcoder, isActive }: Props) => {
const callsMade = useMemo(
() => transcoder?.pools?.filter((r) => r.rewardTokens != null)?.length ?? 0,
[transcoder?.pools]
type ActivationWindow = { start: number; end: number };
type Participation = { voted: number; eligible: number };

const buildActiveWindows = (
activations: { activationRound: string }[],
deactivations: { deactivationRound: string }[]
): ActivationWindow[] => {
const timeline = [
...activations.map((a) => ({
round: Number(a.activationRound),
type: "activation" as const,
})),
...deactivations.map((d) => ({
round: Number(d.deactivationRound),
type: "deactivation" as const,
})),
].sort((a, b) => a.round - b.round || (a.type === "deactivation" ? -1 : 1));
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

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

The sort tiebreaker at line 49 prioritizes deactivation over activation when both events occur in the same round: (a.type === "deactivation" ? -1 : 1). This means that if a transcoder is both activated and deactivated in the same round, the deactivation is processed first.

This could lead to counterintuitive behavior. If the same round has both an activation and deactivation event:

  • With current logic: deactivation comes first, so the activation creates a window starting at that round
  • Expected behavior might be: activation comes first, creating a zero-length or instant window

Consider documenting this behavior or revisiting whether this is the correct handling for same-round activation/deactivation events.

Suggested change
].sort((a, b) => a.round - b.round || (a.type === "deactivation" ? -1 : 1));
].sort((a, b) => {
if (a.round !== b.round) {
return a.round - b.round;
}
if (a.type === b.type) {
return 0;
}
// When in the same round, process activation events before deactivation events
return a.type === "activation" ? -1 : 1;
});

Copilot uses AI. Check for mistakes.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Wondering if this comment sounds reasonable to you @rickstaa . Will ignore if not


const windows: ActivationWindow[] = [];
let start: number | null = null;

for (const { type, round } of timeline) {
if (type === "activation") {
if (start === null) {
start = round;
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

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

The buildActiveWindows function silently ignores activation events that occur when a transcoder is already active (when start !== null). While this may be the expected behavior if the protocol doesn't allow duplicate activations, this silent handling could mask data quality issues.

For robustness, consider either:

  1. Adding a comment documenting this expected behavior
  2. Adding validation to warn if unexpected duplicate activations are encountered
  3. Throwing an error if this case should never occur in practice

This will make the code more maintainable and help future developers understand the assumptions.

Suggested change
start = round;
start = round;
} else {
// Unexpected duplicate activation while a window is already active.
// This is ignored to preserve existing behavior, but logged for visibility.
// If the activation/deactivation protocol guarantees no duplicates, this
// may indicate a data quality issue upstream.
// eslint-disable-next-line no-console
console.warn(
"buildActiveWindows: ignoring duplicate activation event",
{ activeStartRound: start, activationRound: round }
);

Copilot uses AI. Check for mistakes.
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm unsure if the protocol allows duplicate activations @rickstaa so not sure if this suggestion makes sense

}
} else if (start !== null && round >= start) {
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

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

The buildActiveWindows function may not correctly handle deactivation events that occur when start === null (i.e., before any activation). The condition on line 59 checks start !== null && round >= start, so a deactivation event with start === null is simply ignored.

While this might be the intended behavior (deactivation without activation is meaningless), it could silently hide data integrity issues in the underlying events. Consider adding validation or a warning when encountering a deactivation without a prior activation.

Suggested change
} else if (start !== null && round >= start) {
} else if (type === "deactivation") {
if (start === null) {
console.warn(
"buildActiveWindows: received deactivation without a prior activation",
{ deactivationRound: round }
);
continue;
}
if (round < start) {
console.warn(
"buildActiveWindows: received deactivation before the current activation start",
{ activationStartRound: start, deactivationRound: round }
);
continue;
}

Copilot uses AI. Check for mistakes.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Again, it's hard to tell if this is intended since I'm not sure exactly is expected from the protocol

windows.push({ start, end: round });
start = null;
}
}

return start !== null
? [...windows, { start, end: Number.POSITIVE_INFINITY }]
: windows;
};

const isDuringWindow = (round: number, windows: ActivationWindow[]) =>
windows.some((w) => round >= w.start && round < w.end);

const isActiveProposal = (voteStart: string, currentRoundId?: string) =>
currentRoundId ? Number(voteStart) <= Number(currentRoundId) : true;
Copy link
Contributor

@vercel vercel bot Feb 23, 2026

Choose a reason for hiding this comment

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

isActiveProposal function returns true when currentRoundId is undefined, causing all proposals to be considered active regardless of whether their voting has actually started

Fix on Vercel

Copy link
Collaborator

Choose a reason for hiding this comment

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

Seems like this is at least worth sanity-checking. Right now, I can't see a reason why we should default to true


Comment on lines +73 to +75
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

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

The isActiveProposal function returns true when currentRoundId is undefined (line 74). This means all proposals are considered active if the current round ID is not provided. While this might be intentional fallback behavior, it could lead to incorrect participation calculations if the current round ID is unexpectedly missing.

Consider documenting this behavior or making it more explicit with a comment, especially since this affects how "eligible" proposals are counted.

Suggested change
const isActiveProposal = (voteStart: string, currentRoundId?: string) =>
currentRoundId ? Number(voteStart) <= Number(currentRoundId) : true;
const isActiveProposal = (voteStart: string, currentRoundId?: string) => {
// If currentRoundId is not provided, treat all proposals as active.
// This affects how "eligible" proposals are counted in participation metrics.
if (currentRoundId === undefined) {
return true;
}
return Number(voteStart) <= Number(currentRoundId);
};

Copilot uses AI. Check for mistakes.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Agree with this, since I'm finding the logic difficult to follow

const useGovernanceParticipation = (
delegateId?: string,
currentRoundId?: string
): { treasury: Participation | null; loading: boolean } => {
const hasDelegate = Boolean(delegateId);

const { data: activationData, loading: activationLoading } =
useTranscoderActivationHistoryQuery({
...(hasDelegate ? { variables: { delegate: delegateId! } } : {}),
fetchPolicy: "cache-and-network",
skip: !hasDelegate,
});

const { data: votesData, loading: votesLoading } = useTreasuryVotesQuery({
...(hasDelegate ? { variables: { where: { voter: delegateId! } } } : {}),
fetchPolicy: "cache-and-network",
skip: !hasDelegate,
});

const activations = useMemo(
() => activationData?.transcoderActivatedEvents ?? [],
[activationData?.transcoderActivatedEvents]
);
const deactivations = useMemo(
() => activationData?.transcoderDeactivatedEvents ?? [],
[activationData?.transcoderDeactivatedEvents]
);

const scores = useScoreData(transcoder?.id);
const knownRegions = useRegionsData();
const firstActivationRound = activations[0]?.activationRound;

const { data: firstTranscoderActivatedEventsData } =
useTranscoderActivatedEventsQuery({
variables: {
where: {
delegate: transcoder?.id,
},
first: 1,
orderBy: TranscoderActivatedEvent_OrderBy.ActivationRound,
orderDirection: OrderDirection.Asc,
},
const windows = useMemo(
() => buildActiveWindows(activations, deactivations),
[activations, deactivations]
);

const { data: proposalsData, loading: proposalsLoading } =
useTreasuryProposalsQuery({
variables: firstActivationRound
? { where: { voteStart_gte: firstActivationRound } }
Copy link
Contributor

@vercel vercel bot Feb 23, 2026

Choose a reason for hiding this comment

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

Vote count can exceed eligible proposal count due to asymmetric filtering between proposals and votes queries

Fix on Vercel

Copy link
Collaborator

Choose a reason for hiding this comment

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

The suggestion of Number(vote.proposal.voteStart) >= Number(firstActivationRound) && on line 131 seems reasonable to me

: undefined,
skip: !firstActivationRound,
fetchPolicy: "cache-and-network",
});

const firstActivationRound = useMemo(() => {
return firstTranscoderActivatedEventsData?.transcoderActivatedEvents[0]
?.activationRound;
}, [firstTranscoderActivatedEventsData]);
const treasuryParticipation = useMemo<Participation | null>(() => {
if (!proposalsData || !votesData) return null;
if (!firstActivationRound) return null;

const { data: treasuryVotesData } = useTreasuryVotesQuery({
variables: {
where: {
voter: transcoder?.id,
},
},
});
const eligible = proposalsData.treasuryProposals.filter(
(proposal) =>
isActiveProposal(proposal.voteStart, currentRoundId) &&
isDuringWindow(Number(proposal.voteStart), windows)
).length;
const voted = votesData.treasuryVotes.filter(
(vote) =>
isActiveProposal(vote.proposal.voteStart, currentRoundId) &&
isDuringWindow(Number(vote.proposal.voteStart), windows)
).length;
return { voted, eligible };
}, [proposalsData, votesData, firstActivationRound, windows, currentRoundId]);

const { data: eligebleProposalsData } = useTreasuryProposalsQuery({
variables: {
where: {
voteStart_gt: firstActivationRound,
},
},
skip: !firstActivationRound,
});
return {
treasury: treasuryParticipation,
loading: activationLoading || votesLoading || proposalsLoading,
};
};

const govStats = useMemo(() => {
if (!treasuryVotesData || !eligebleProposalsData) return null;
return {
voted: treasuryVotesData?.treasuryVotes.length ?? 0,
eligible: eligebleProposalsData?.treasuryProposals.length ?? 0,
};
}, [treasuryVotesData, eligebleProposalsData]);
const Index = ({ currentRound, transcoder, isActive }: Props) => {
const callsMade = useMemo(
() => transcoder?.pools?.filter((r) => r.rewardTokens != null)?.length ?? 0,
[transcoder?.pools]
);

const scores = useScoreData(transcoder?.id);
const knownRegions = useRegionsData();
const { treasury: govStats } = useGovernanceParticipation(
transcoder?.id,
currentRound?.id
);

const maxScore = useMemo(() => {
const topTransData = Object.keys(scores?.scores ?? {}).reduce(
Expand Down Expand Up @@ -145,6 +215,9 @@ const Index = ({ currentRound, transcoder, isActive }: Props) => {
: { score: "N/A", modelText: "" };
}, [knownRegions?.regions, maxScore]);

const govParticipation =
govStats && govStats.eligible > 0 ? govStats.voted / govStats.eligible : 0;

return (
<Box
css={{
Expand Down Expand Up @@ -389,7 +462,7 @@ const Index = ({ currentRound, transcoder, isActive }: Props) => {
>
<Box
css={{
width: `${(govStats.voted / govStats.eligible) * 100}%`,
width: `${govParticipation * 100}%`,
height: "100%",
backgroundColor: "$primary11",
}}
Expand All @@ -408,7 +481,7 @@ const Index = ({ currentRound, transcoder, isActive }: Props) => {
size="2"
css={{ color: "$neutral11", fontWeight: 600 }}
>
{numbro(govStats.voted / govStats.eligible).format({
{numbro(govParticipation).format({
output: "percent",
mantissa: 0,
})}{" "}
Expand Down
16 changes: 0 additions & 16 deletions queries/transcoderActivatedEvents.graphql

This file was deleted.

16 changes: 16 additions & 0 deletions queries/transcoderActivationHistory.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
query transcoderActivationHistory($delegate: String!) {
transcoderActivatedEvents(
where: { delegate: $delegate }
orderBy: activationRound
orderDirection: asc
) {
activationRound
}
transcoderDeactivatedEvents(
where: { delegate: $delegate }
orderBy: deactivationRound
orderDirection: asc
) {
deactivationRound
}
}