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 === "activation" ? -1 : 1));

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

for (const { type, round } of timeline) {
if (type === "activation") {
if (start === null) {
start = round;
}
} else if (start !== null && round >= start) {
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) : false;

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 } }
: 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
}
}