Skip to content
Merged
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
24 changes: 21 additions & 3 deletions apollo/subgraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5764,8 +5764,8 @@ export type Transaction = {
id: Scalars['ID'];
/** Timestamp for transaction */
timestamp: Scalars['Int'];
/** The receiving party of the transaction */
to: Scalars['String'];
/** The receiving party of the transaction - null for contract-creation transactions */
to?: Maybe<Scalars['String']>;
};


Expand Down Expand Up @@ -9707,7 +9707,7 @@ 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', 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 }, sender: { __typename: 'Broadcaster', id: string }, recipient: { __typename: 'Transcoder', id: string } }> };
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', 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 }, sender: { __typename: 'Broadcaster', id: string }, recipient: { __typename: 'Transcoder', id: string } }>, rewardEvents: Array<{ __typename: 'RewardEvent', id: string, rewardTokens: string, round: { __typename: 'Round', id: string }, transaction: { __typename: 'Transaction', id: string, timestamp: number } }> };

export type TranscoderActivatedEventsQueryVariables = Exact<{
where?: InputMaybe<TranscoderActivatedEvent_Filter>;
Expand Down Expand Up @@ -10781,6 +10781,24 @@ export const TransactionsDocument = gql`
id
}
}
rewardEvents(
orderBy: timestamp
orderDirection: desc
where: {delegate: $account}
first: $first
skip: $skip
) {
__typename
id
round {
id
}
transaction {
id
timestamp
}
rewardTokens
}
}
`;

Expand Down
44 changes: 35 additions & 9 deletions components/HistoryView/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ const Index = () => {
const isVoteEvent = isType("VoteEvent");
const isTreasuryVoteEvent = isType("TreasuryVoteEvent");

// Clamps tickets/rewards to the oldest loaded transaction so rows only
// append; nothing is stranded, registration precedes both.
const lastEventTimestamp = useMemo(
() =>
Number(events?.[(events?.length || 0) - 1]?.transaction?.timestamp ?? 0),
Expand Down Expand Up @@ -170,18 +172,30 @@ const Index = () => {
}));
}, [data?.winningTicketRedeemedEvents, account, lastEventTimestamp]);

// WinningTicketRedeemedEvents, VoteEvents, and TreasuryVoteEvents are replaced
// with enriched versions (direction-tagged tickets, IPFS-enriched votes)
// Orchestrator-keyed so delegated reward calls, whose transaction is sent by
// the reward caller, are included too.
const rewardEvents = useMemo(
() =>
data?.rewardEvents?.filter(
(e) => (e?.transaction?.timestamp ?? 0) > lastEventTimestamp
) ?? [],
Comment thread
rickstaa marked this conversation as resolved.
[data?.rewardEvents, lastEventTimestamp]
);

const mergedEvents = useMemo(
() =>
[
// Dropped here and re-added below from the enriched (tickets, votes)
// and superset (rewards) lists, so they are not listed twice.
...events.filter(
(e) =>
e?.__typename !== "WinningTicketRedeemedEvent" &&
e?.__typename !== "TreasuryVoteEvent" &&
e?.__typename !== "VoteEvent"
e?.__typename !== "VoteEvent" &&
e?.__typename !== "RewardEvent"
),
...ticketEvents,
...rewardEvents,
...extendedTreasuryVoteEventsData,
...extendedVoteEventsData,
].sort(
Expand All @@ -191,14 +205,16 @@ const Index = () => {
[
events,
ticketEvents,
rewardEvents,
extendedTreasuryVoteEventsData,
extendedVoteEventsData,
]
);

const totalLoaded = Math.max(
data?.transactions?.length ?? 0,
data?.winningTicketRedeemedEvents?.length ?? 0
data?.winningTicketRedeemedEvents?.length ?? 0,
data?.rewardEvents?.length ?? 0
);

const fetchingRef = useRef(false);
Expand All @@ -210,11 +226,19 @@ const Index = () => {
try {
await fetchMoreTransactions({
variables: {
// Shared skip: a shorter list is only over-skipped once exhausted.
skip: totalLoaded,
},
updateQuery: (previousResult, { fetchMoreResult }) => {
if (!fetchMoreResult) return previousResult;
if (fetchMoreResult.transactions.length < PAGE_SIZE)
// Stop only once every list is exhausted. Rewards and ticket
// redemptions can be submitted by another address, so neither list is
// bounded by `transactions`.
if (
fetchMoreResult.transactions.length < PAGE_SIZE &&
fetchMoreResult.winningTicketRedeemedEvents.length < PAGE_SIZE &&
fetchMoreResult.rewardEvents.length < PAGE_SIZE
)
setReachedEnd(true);

return {
Expand All @@ -223,13 +247,14 @@ const Index = () => {
...previousResult.transactions,
...fetchMoreResult.transactions,
],
// Basing the query skip for winning tickets on transactions.length is fine because there will always be more transactions than winning tickets
// So, we will always have winning ticket events that are older than the last transaction timestamp
// Allowing mergedEvents to filter correctly
winningTicketRedeemedEvents: [
...previousResult.winningTicketRedeemedEvents,
...fetchMoreResult.winningTicketRedeemedEvents,
],
rewardEvents: [
...previousResult.rewardEvents,
...fetchMoreResult.rewardEvents,
],
};
},
});
Expand Down Expand Up @@ -276,7 +301,8 @@ const Index = () => {

if (
!data?.transactions?.length &&
!data?.winningTicketRedeemedEvents?.length
!data?.winningTicketRedeemedEvents?.length &&
!data?.rewardEvents?.length
) {
return <Box css={{ paddingTop: "$3" }}>No history</Box>;
}
Expand Down
22 changes: 22 additions & 0 deletions queries/transactions.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -132,4 +132,26 @@ query transactions($account: String!, $first: Int!, $skip: Int!) {
id
}
}
# Keyed on the orchestrator (RewardEvent.delegate), not the transaction sender.
# Since LIP-118 a delegated reward caller may submit reward() on the
# orchestrator's behalf, so those calls are absent from the transactions query
# above, which filters on `from`.
rewardEvents(
orderBy: timestamp
orderDirection: desc
where: { delegate: $account }
first: $first
skip: $skip
) {
__typename
id
round {
id
}
transaction {
id
timestamp
}
rewardTokens
}
}
Loading