feat(governance): see user stake on validators table (#3250)
Co-authored-by: Joe <joe@vega.xyz>
This commit is contained in:
parent
c25858037a
commit
eca212eee0
@ -74,7 +74,7 @@ context('Validators Page - verify elements on page', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Should be able to see validator stake', function () {
|
it('Should be able to see validator stake', function () {
|
||||||
cy.get('[col-id="stake"] > div > span > span')
|
cy.getByTestId('total-stake')
|
||||||
.should('have.length.at.least', 1)
|
.should('have.length.at.least', 1)
|
||||||
.each(($stake) => {
|
.each(($stake) => {
|
||||||
cy.wrap($stake).should('not.be.empty');
|
cy.wrap($stake).should('not.be.empty');
|
||||||
@ -82,7 +82,7 @@ context('Validators Page - verify elements on page', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Should be able to see validator stake tooltip', function () {
|
it('Should be able to see validator stake tooltip', function () {
|
||||||
cy.get('[col-id="stake"] > div > span > span').first().realHover();
|
cy.getByTestId('total-stake').first().realHover();
|
||||||
|
|
||||||
cy.get(stakedByOperatorToolTip)
|
cy.get(stakedByOperatorToolTip)
|
||||||
.invoke('text')
|
.invoke('text')
|
||||||
@ -96,17 +96,15 @@ context('Validators Page - verify elements on page', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Should be able to see validator normalised voting power', function () {
|
it('Should be able to see validator normalised voting power', function () {
|
||||||
cy.get('[col-id="normalisedVotingPower"] > div > span > span')
|
cy.getByTestId('normalised-voting-power')
|
||||||
.should('have.length.at.least', 1)
|
.should('have.length.at.least', 1)
|
||||||
.each(($vPower) => {
|
.each(($vPower) => {
|
||||||
cy.wrap($vPower).should('not.be.empty');
|
cy.wrap($vPower).should('not.be.empty');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should be able to see validator voting power tooltip', function () {
|
it('Should be able to see validator normalised voting power tooltip', function () {
|
||||||
cy.get('[col-id="normalisedVotingPower"] > div > span > span')
|
cy.getByTestId('normalised-voting-power').first().realHover();
|
||||||
.first()
|
|
||||||
.realHover();
|
|
||||||
|
|
||||||
cy.get(unnormalisedVotingPowerToolTip)
|
cy.get(unnormalisedVotingPowerToolTip)
|
||||||
.invoke('text')
|
.invoke('text')
|
||||||
@ -118,7 +116,7 @@ context('Validators Page - verify elements on page', function () {
|
|||||||
|
|
||||||
// 2002-SINC-018
|
// 2002-SINC-018
|
||||||
it('Should be able to see validator total penalties', function () {
|
it('Should be able to see validator total penalties', function () {
|
||||||
cy.get('[col-id="totalPenalties"] > div > span > span')
|
cy.getByTestId('total-penalty')
|
||||||
.should('have.length.at.least', 1)
|
.should('have.length.at.least', 1)
|
||||||
.each(($penalties) => {
|
.each(($penalties) => {
|
||||||
cy.wrap($penalties).should('contain.text', '0%');
|
cy.wrap($penalties).should('contain.text', '0%');
|
||||||
@ -126,7 +124,7 @@ context('Validators Page - verify elements on page', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Should be able to see validator penalties tooltip', function () {
|
it('Should be able to see validator penalties tooltip', function () {
|
||||||
cy.get('[col-id="totalPenalties"] > div > span > span').realHover();
|
cy.getByTestId('total-penalty').realHover();
|
||||||
|
|
||||||
cy.get(performancePenaltyToolTip)
|
cy.get(performancePenaltyToolTip)
|
||||||
.invoke('text')
|
.invoke('text')
|
||||||
@ -140,7 +138,7 @@ context('Validators Page - verify elements on page', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Should be able to see validator pending stake', function () {
|
it('Should be able to see validator pending stake', function () {
|
||||||
cy.get('[col-id="pendingStake"] > div > span')
|
cy.getByTestId('total-pending-stake')
|
||||||
.should('have.length.at.least', 1)
|
.should('have.length.at.least', 1)
|
||||||
.each(($pendingStake) => {
|
.each(($pendingStake) => {
|
||||||
cy.wrap($pendingStake).should('contain.text', '0.00');
|
cy.wrap($pendingStake).should('contain.text', '0.00');
|
||||||
|
@ -14,8 +14,8 @@ const associateWalletRadioButton = '[data-testid="associate-radio-wallet"]';
|
|||||||
const associateContractRadioButton = '[data-testid="associate-radio-contract"]';
|
const associateContractRadioButton = '[data-testid="associate-radio-contract"]';
|
||||||
const stakeMaximumTokens = '[data-testid="token-amount-use-maximum"]';
|
const stakeMaximumTokens = '[data-testid="token-amount-use-maximum"]';
|
||||||
const stakeValidatorListPendingStake = '[col-id="pendingStake"]';
|
const stakeValidatorListPendingStake = '[col-id="pendingStake"]';
|
||||||
const stakeValidatorListTotalStake = '[col-id="stake"] > div > span';
|
const stakeValidatorListTotalStake = 'total-stake';
|
||||||
const stakeValidatorListTotalShare = '[col-id="stakeShare"] > div > span';
|
const stakeValidatorListTotalShare = 'total-stake-share';
|
||||||
const stakeValidatorListName = '[col-id="validator"]';
|
const stakeValidatorListName = '[col-id="validator"]';
|
||||||
const vegaKeySelector = '#vega-key-selector';
|
const vegaKeySelector = '#vega-key-selector';
|
||||||
const dialogCloseButton = '[data-testid="dialog-close"]';
|
const dialogCloseButton = '[data-testid="dialog-close"]';
|
||||||
@ -185,11 +185,11 @@ export function validateValidatorListTotalStakeAndShare(
|
|||||||
cy.contains('Loading...', epochTimeout).should('not.exist');
|
cy.contains('Loading...', epochTimeout).should('not.exist');
|
||||||
waitForBeginningOfEpoch();
|
waitForBeginningOfEpoch();
|
||||||
cy.get(`[row-id="${positionOnList}"]`).within(() => {
|
cy.get(`[row-id="${positionOnList}"]`).within(() => {
|
||||||
cy.get(stakeValidatorListTotalStake, epochTimeout).should(
|
cy.getByTestId(stakeValidatorListTotalStake, epochTimeout).should(
|
||||||
'have.text',
|
'have.text',
|
||||||
expectedTotalStake
|
expectedTotalStake
|
||||||
);
|
);
|
||||||
cy.get(stakeValidatorListTotalShare, epochTimeout).should(
|
cy.getByTestId(stakeValidatorListTotalShare, epochTimeout).should(
|
||||||
'have.text',
|
'have.text',
|
||||||
expectedTotalShare
|
expectedTotalShare
|
||||||
);
|
);
|
||||||
|
@ -602,11 +602,14 @@
|
|||||||
"noValidators": "No validators",
|
"noValidators": "No validators",
|
||||||
"validator": "Validator",
|
"validator": "Validator",
|
||||||
"stake": "Stake",
|
"stake": "Stake",
|
||||||
|
"myStake": "My stake",
|
||||||
"stakeShare": "Stake share",
|
"stakeShare": "Stake share",
|
||||||
"stakedByOperator": "Staked by operator",
|
"stakedByOperator": "Staked by operator",
|
||||||
"stakedByDelegates": "Staked by delegates",
|
"stakedByDelegates": "Staked by delegates",
|
||||||
|
"stakedByMe": "Staked by me",
|
||||||
"totalStake": "Total stake",
|
"totalStake": "Total stake",
|
||||||
"pendingStake": "Pending stake",
|
"pendingStake": "Pending stake",
|
||||||
|
"myPendingStake": "My pending stake",
|
||||||
"totalPenalties": "Total penalties",
|
"totalPenalties": "Total penalties",
|
||||||
"noPenaltyDataFromLastEpoch": "No penalty data from last epoch",
|
"noPenaltyDataFromLastEpoch": "No penalty data from last epoch",
|
||||||
"stakeNeededForPromotion": "Stake needed for promotion",
|
"stakeNeededForPromotion": "Stake needed for promotion",
|
||||||
|
@ -12,14 +12,14 @@ import { useRefreshAfterEpoch } from '../../hooks/use-refresh-after-epoch';
|
|||||||
import { ProposalsListItem } from '../proposals/components/proposals-list-item';
|
import { ProposalsListItem } from '../proposals/components/proposals-list-item';
|
||||||
import Routes from '../routes';
|
import Routes from '../routes';
|
||||||
import { ExternalLinks, removePaginationWrapper } from '@vegaprotocol/utils';
|
import { ExternalLinks, removePaginationWrapper } from '@vegaprotocol/utils';
|
||||||
import { useNodesQuery } from '../staking/home/__generated___/Nodes';
|
import { useNodesQuery } from '../staking/home/__generated__/Nodes';
|
||||||
import { useProposalsQuery } from '../proposals/proposals/__generated__/Proposals';
|
import { useProposalsQuery } from '../proposals/proposals/__generated__/Proposals';
|
||||||
import { getNotRejectedProposals } from '../proposals/proposals/proposals-container';
|
import { getNotRejectedProposals } from '../proposals/proposals/proposals-container';
|
||||||
import { Heading } from '../../components/heading';
|
import { Heading } from '../../components/heading';
|
||||||
import * as Schema from '@vegaprotocol/types';
|
import * as Schema from '@vegaprotocol/types';
|
||||||
import type { RouteChildProps } from '..';
|
import type { RouteChildProps } from '..';
|
||||||
import type { ProposalFieldsFragment } from '../proposals/proposals/__generated__/Proposals';
|
import type { ProposalFieldsFragment } from '../proposals/proposals/__generated__/Proposals';
|
||||||
import type { NodesFragmentFragment } from '../staking/home/__generated___/Nodes';
|
import type { NodesFragmentFragment } from '../staking/home/__generated__/Nodes';
|
||||||
|
|
||||||
const nodesToShow = 6;
|
const nodesToShow = 6;
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ export const RewardsPage = () => {
|
|||||||
</section>
|
</section>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<section className="grid xl:grid-cols-2 gap-12 items-center mb-8">
|
<section className="grid xl:grid-cols-[1fr_auto] gap-12 items-center mb-8">
|
||||||
<div>
|
<div>
|
||||||
<SubHeading title={t('rewardsAndFeesReceived')} />
|
<SubHeading title={t('rewardsAndFeesReceived')} />
|
||||||
<p>
|
<p>
|
||||||
@ -114,7 +114,7 @@ export const RewardsPage = () => {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="max-w-[600px]">
|
<div className="w-[440px]">
|
||||||
<Toggle
|
<Toggle
|
||||||
name="epoch-reward-view-toggle"
|
name="epoch-reward-view-toggle"
|
||||||
toggles={[
|
toggles={[
|
||||||
|
@ -23,6 +23,17 @@ fragment StakingNodeFields on Node {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fragment StakingDelegationFields on Delegation {
|
||||||
|
amount
|
||||||
|
epoch
|
||||||
|
node {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
party {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
query Staking($partyId: ID!, $delegationsPagination: Pagination) {
|
query Staking($partyId: ID!, $delegationsPagination: Pagination) {
|
||||||
party(id: $partyId) {
|
party(id: $partyId) {
|
||||||
id
|
id
|
||||||
@ -32,11 +43,7 @@ query Staking($partyId: ID!, $delegationsPagination: Pagination) {
|
|||||||
delegationsConnection(pagination: $delegationsPagination) {
|
delegationsConnection(pagination: $delegationsPagination) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
amount
|
...StakingDelegationFields
|
||||||
epoch
|
|
||||||
node {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,13 +5,15 @@ import * as Apollo from '@apollo/client';
|
|||||||
const defaultOptions = {} as const;
|
const defaultOptions = {} as const;
|
||||||
export type StakingNodeFieldsFragment = { __typename?: 'Node', id: string, name: string, pubkey: string, infoUrl: string, location: string, ethereumAddress: string, stakedByOperator: string, stakedByDelegates: string, stakedTotal: string, pendingStake: string, epochData?: { __typename?: 'EpochData', total: number, offline: number, online: number } | null, rankingScore: { __typename?: 'RankingScore', rankingScore: string, stakeScore: string, performanceScore: string, votingPower: string, status: Types.ValidatorStatus } };
|
export type StakingNodeFieldsFragment = { __typename?: 'Node', id: string, name: string, pubkey: string, infoUrl: string, location: string, ethereumAddress: string, stakedByOperator: string, stakedByDelegates: string, stakedTotal: string, pendingStake: string, epochData?: { __typename?: 'EpochData', total: number, offline: number, online: number } | null, rankingScore: { __typename?: 'RankingScore', rankingScore: string, stakeScore: string, performanceScore: string, votingPower: string, status: Types.ValidatorStatus } };
|
||||||
|
|
||||||
|
export type StakingDelegationFieldsFragment = { __typename?: 'Delegation', amount: string, epoch: number, node: { __typename?: 'Node', id: string }, party: { __typename?: 'Party', id: string } };
|
||||||
|
|
||||||
export type StakingQueryVariables = Types.Exact<{
|
export type StakingQueryVariables = Types.Exact<{
|
||||||
partyId: Types.Scalars['ID'];
|
partyId: Types.Scalars['ID'];
|
||||||
delegationsPagination?: Types.InputMaybe<Types.Pagination>;
|
delegationsPagination?: Types.InputMaybe<Types.Pagination>;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type StakingQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, stakingSummary: { __typename?: 'StakingSummary', currentStakeAvailable: string }, delegationsConnection?: { __typename?: 'DelegationsConnection', edges?: Array<{ __typename?: 'DelegationEdge', node: { __typename?: 'Delegation', amount: string, epoch: number, node: { __typename?: 'Node', id: string } } } | null> | null } | null } | null, epoch: { __typename?: 'Epoch', id: string, timestamps: { __typename?: 'EpochTimestamps', start?: any | null, end?: any | null, expiry?: any | null } }, nodesConnection: { __typename?: 'NodesConnection', edges?: Array<{ __typename?: 'NodeEdge', node: { __typename?: 'Node', id: string, name: string, pubkey: string, infoUrl: string, location: string, ethereumAddress: string, stakedByOperator: string, stakedByDelegates: string, stakedTotal: string, pendingStake: string, epochData?: { __typename?: 'EpochData', total: number, offline: number, online: number } | null, rankingScore: { __typename?: 'RankingScore', rankingScore: string, stakeScore: string, performanceScore: string, votingPower: string, status: Types.ValidatorStatus } } } | null> | null }, nodeData?: { __typename?: 'NodeData', stakedTotal: string, totalNodes: number, inactiveNodes: number, uptime: number } | null };
|
export type StakingQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, stakingSummary: { __typename?: 'StakingSummary', currentStakeAvailable: string }, delegationsConnection?: { __typename?: 'DelegationsConnection', edges?: Array<{ __typename?: 'DelegationEdge', node: { __typename?: 'Delegation', amount: string, epoch: number, node: { __typename?: 'Node', id: string }, party: { __typename?: 'Party', id: string } } } | null> | null } | null } | null, epoch: { __typename?: 'Epoch', id: string, timestamps: { __typename?: 'EpochTimestamps', start?: any | null, end?: any | null, expiry?: any | null } }, nodesConnection: { __typename?: 'NodesConnection', edges?: Array<{ __typename?: 'NodeEdge', node: { __typename?: 'Node', id: string, name: string, pubkey: string, infoUrl: string, location: string, ethereumAddress: string, stakedByOperator: string, stakedByDelegates: string, stakedTotal: string, pendingStake: string, epochData?: { __typename?: 'EpochData', total: number, offline: number, online: number } | null, rankingScore: { __typename?: 'RankingScore', rankingScore: string, stakeScore: string, performanceScore: string, votingPower: string, status: Types.ValidatorStatus } } } | null> | null }, nodeData?: { __typename?: 'NodeData', stakedTotal: string, totalNodes: number, inactiveNodes: number, uptime: number } | null };
|
||||||
|
|
||||||
export const StakingNodeFieldsFragmentDoc = gql`
|
export const StakingNodeFieldsFragmentDoc = gql`
|
||||||
fragment StakingNodeFields on Node {
|
fragment StakingNodeFields on Node {
|
||||||
@ -39,6 +41,18 @@ export const StakingNodeFieldsFragmentDoc = gql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
export const StakingDelegationFieldsFragmentDoc = gql`
|
||||||
|
fragment StakingDelegationFields on Delegation {
|
||||||
|
amount
|
||||||
|
epoch
|
||||||
|
node {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
party {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
export const StakingDocument = gql`
|
export const StakingDocument = gql`
|
||||||
query Staking($partyId: ID!, $delegationsPagination: Pagination) {
|
query Staking($partyId: ID!, $delegationsPagination: Pagination) {
|
||||||
party(id: $partyId) {
|
party(id: $partyId) {
|
||||||
@ -49,11 +63,7 @@ export const StakingDocument = gql`
|
|||||||
delegationsConnection(pagination: $delegationsPagination) {
|
delegationsConnection(pagination: $delegationsPagination) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
amount
|
...StakingDelegationFields
|
||||||
epoch
|
|
||||||
node {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -80,6 +90,7 @@ export const StakingDocument = gql`
|
|||||||
uptime
|
uptime
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
${StakingDelegationFieldsFragmentDoc}
|
||||||
${StakingNodeFieldsFragmentDoc}`;
|
${StakingNodeFieldsFragmentDoc}`;
|
||||||
|
|
||||||
/**
|
/**
|
@ -1,106 +0,0 @@
|
|||||||
import * as Types from '@vegaprotocol/types';
|
|
||||||
|
|
||||||
import { gql } from '@apollo/client';
|
|
||||||
import * as Apollo from '@apollo/client';
|
|
||||||
const defaultOptions = {} as const;
|
|
||||||
export type PreviousEpochQueryVariables = Types.Exact<{
|
|
||||||
epochId?: Types.InputMaybe<Types.Scalars['ID']>;
|
|
||||||
}>;
|
|
||||||
|
|
||||||
export type PreviousEpochQuery = {
|
|
||||||
__typename?: 'Query';
|
|
||||||
epoch: {
|
|
||||||
__typename?: 'Epoch';
|
|
||||||
id: string;
|
|
||||||
validatorsConnection?: {
|
|
||||||
__typename?: 'NodesConnection';
|
|
||||||
edges?: Array<{
|
|
||||||
__typename?: 'NodeEdge';
|
|
||||||
node: {
|
|
||||||
__typename?: 'Node';
|
|
||||||
id: string;
|
|
||||||
rewardScore?: {
|
|
||||||
__typename?: 'RewardScore';
|
|
||||||
rawValidatorScore: string;
|
|
||||||
} | null;
|
|
||||||
rankingScore: {
|
|
||||||
__typename?: 'RankingScore';
|
|
||||||
performanceScore: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
} | null> | null;
|
|
||||||
} | null;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const PreviousEpochDocument = gql`
|
|
||||||
query PreviousEpoch($epochId: ID) {
|
|
||||||
epoch(id: $epochId) {
|
|
||||||
id
|
|
||||||
validatorsConnection {
|
|
||||||
edges {
|
|
||||||
node {
|
|
||||||
id
|
|
||||||
rewardScore {
|
|
||||||
rawValidatorScore
|
|
||||||
}
|
|
||||||
rankingScore {
|
|
||||||
performanceScore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* __usePreviousEpochQuery__
|
|
||||||
*
|
|
||||||
* To run a query within a React component, call `usePreviousEpochQuery` and pass it any options that fit your needs.
|
|
||||||
* When your component renders, `usePreviousEpochQuery` 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 } = usePreviousEpochQuery({
|
|
||||||
* variables: {
|
|
||||||
* epochId: // value for 'epochId'
|
|
||||||
* },
|
|
||||||
* });
|
|
||||||
*/
|
|
||||||
export function usePreviousEpochQuery(
|
|
||||||
baseOptions?: Apollo.QueryHookOptions<
|
|
||||||
PreviousEpochQuery,
|
|
||||||
PreviousEpochQueryVariables
|
|
||||||
>
|
|
||||||
) {
|
|
||||||
const options = { ...defaultOptions, ...baseOptions };
|
|
||||||
return Apollo.useQuery<PreviousEpochQuery, PreviousEpochQueryVariables>(
|
|
||||||
PreviousEpochDocument,
|
|
||||||
options
|
|
||||||
);
|
|
||||||
}
|
|
||||||
export function usePreviousEpochLazyQuery(
|
|
||||||
baseOptions?: Apollo.LazyQueryHookOptions<
|
|
||||||
PreviousEpochQuery,
|
|
||||||
PreviousEpochQueryVariables
|
|
||||||
>
|
|
||||||
) {
|
|
||||||
const options = { ...defaultOptions, ...baseOptions };
|
|
||||||
return Apollo.useLazyQuery<PreviousEpochQuery, PreviousEpochQueryVariables>(
|
|
||||||
PreviousEpochDocument,
|
|
||||||
options
|
|
||||||
);
|
|
||||||
}
|
|
||||||
export type PreviousEpochQueryHookResult = ReturnType<
|
|
||||||
typeof usePreviousEpochQuery
|
|
||||||
>;
|
|
||||||
export type PreviousEpochLazyQueryHookResult = ReturnType<
|
|
||||||
typeof usePreviousEpochLazyQuery
|
|
||||||
>;
|
|
||||||
export type PreviousEpochQueryResult = Apollo.QueryResult<
|
|
||||||
PreviousEpochQuery,
|
|
||||||
PreviousEpochQueryVariables
|
|
||||||
>;
|
|
@ -1,114 +0,0 @@
|
|||||||
import * as Types from '@vegaprotocol/types';
|
|
||||||
|
|
||||||
import { gql } from '@apollo/client';
|
|
||||||
import * as Apollo from '@apollo/client';
|
|
||||||
const defaultOptions = {} as const;
|
|
||||||
export type LinkingsFieldsFragment = {
|
|
||||||
__typename?: 'StakeLinking';
|
|
||||||
id: string;
|
|
||||||
txHash: string;
|
|
||||||
status: Types.StakeLinkingStatus;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PartyStakeLinkingsQueryVariables = Types.Exact<{
|
|
||||||
partyId: Types.Scalars['ID'];
|
|
||||||
}>;
|
|
||||||
|
|
||||||
export type PartyStakeLinkingsQuery = {
|
|
||||||
__typename?: 'Query';
|
|
||||||
party?: {
|
|
||||||
__typename?: 'Party';
|
|
||||||
id: string;
|
|
||||||
stakingSummary: {
|
|
||||||
__typename?: 'StakingSummary';
|
|
||||||
linkings: {
|
|
||||||
__typename?: 'StakesConnection';
|
|
||||||
edges?: Array<{
|
|
||||||
__typename?: 'StakeLinkingEdge';
|
|
||||||
node: {
|
|
||||||
__typename?: 'StakeLinking';
|
|
||||||
id: string;
|
|
||||||
txHash: string;
|
|
||||||
status: Types.StakeLinkingStatus;
|
|
||||||
};
|
|
||||||
} | null> | null;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
} | null;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const LinkingsFieldsFragmentDoc = gql`
|
|
||||||
fragment LinkingsFields on StakeLinking {
|
|
||||||
id
|
|
||||||
txHash
|
|
||||||
status
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
export const PartyStakeLinkingsDocument = gql`
|
|
||||||
query PartyStakeLinkings($partyId: ID!) {
|
|
||||||
party(id: $partyId) {
|
|
||||||
id
|
|
||||||
stakingSummary {
|
|
||||||
linkings {
|
|
||||||
edges {
|
|
||||||
node {
|
|
||||||
...LinkingsFields
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
${LinkingsFieldsFragmentDoc}
|
|
||||||
`;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* __usePartyStakeLinkingsQuery__
|
|
||||||
*
|
|
||||||
* To run a query within a React component, call `usePartyStakeLinkingsQuery` and pass it any options that fit your needs.
|
|
||||||
* When your component renders, `usePartyStakeLinkingsQuery` 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 } = usePartyStakeLinkingsQuery({
|
|
||||||
* variables: {
|
|
||||||
* partyId: // value for 'partyId'
|
|
||||||
* },
|
|
||||||
* });
|
|
||||||
*/
|
|
||||||
export function usePartyStakeLinkingsQuery(
|
|
||||||
baseOptions: Apollo.QueryHookOptions<
|
|
||||||
PartyStakeLinkingsQuery,
|
|
||||||
PartyStakeLinkingsQueryVariables
|
|
||||||
>
|
|
||||||
) {
|
|
||||||
const options = { ...defaultOptions, ...baseOptions };
|
|
||||||
return Apollo.useQuery<
|
|
||||||
PartyStakeLinkingsQuery,
|
|
||||||
PartyStakeLinkingsQueryVariables
|
|
||||||
>(PartyStakeLinkingsDocument, options);
|
|
||||||
}
|
|
||||||
export function usePartyStakeLinkingsLazyQuery(
|
|
||||||
baseOptions?: Apollo.LazyQueryHookOptions<
|
|
||||||
PartyStakeLinkingsQuery,
|
|
||||||
PartyStakeLinkingsQueryVariables
|
|
||||||
>
|
|
||||||
) {
|
|
||||||
const options = { ...defaultOptions, ...baseOptions };
|
|
||||||
return Apollo.useLazyQuery<
|
|
||||||
PartyStakeLinkingsQuery,
|
|
||||||
PartyStakeLinkingsQueryVariables
|
|
||||||
>(PartyStakeLinkingsDocument, options);
|
|
||||||
}
|
|
||||||
export type PartyStakeLinkingsQueryHookResult = ReturnType<
|
|
||||||
typeof usePartyStakeLinkingsQuery
|
|
||||||
>;
|
|
||||||
export type PartyStakeLinkingsLazyQueryHookResult = ReturnType<
|
|
||||||
typeof usePartyStakeLinkingsLazyQuery
|
|
||||||
>;
|
|
||||||
export type PartyStakeLinkingsQueryResult = Apollo.QueryResult<
|
|
||||||
PartyStakeLinkingsQuery,
|
|
||||||
PartyStakeLinkingsQueryVariables
|
|
||||||
>;
|
|
@ -15,7 +15,7 @@ import {
|
|||||||
} from '../../../hooks/transaction-reducer';
|
} from '../../../hooks/transaction-reducer';
|
||||||
import Routes from '../../routes';
|
import Routes from '../../routes';
|
||||||
import { truncateMiddle } from '../../../lib/truncate-middle';
|
import { truncateMiddle } from '../../../lib/truncate-middle';
|
||||||
import type { LinkingsFieldsFragment } from './__generated___/PartyStakeLinkings';
|
import type { LinkingsFieldsFragment } from './__generated__/PartyStakeLinkings';
|
||||||
|
|
||||||
export const AssociateTransaction = ({
|
export const AssociateTransaction = ({
|
||||||
amount,
|
amount,
|
||||||
|
@ -15,8 +15,8 @@ import type {
|
|||||||
LinkingsFieldsFragment,
|
LinkingsFieldsFragment,
|
||||||
PartyStakeLinkingsQuery,
|
PartyStakeLinkingsQuery,
|
||||||
PartyStakeLinkingsQueryVariables,
|
PartyStakeLinkingsQueryVariables,
|
||||||
} from './__generated___/PartyStakeLinkings';
|
} from './__generated__/PartyStakeLinkings';
|
||||||
import { PartyStakeLinkingsDocument } from './__generated___/PartyStakeLinkings';
|
import { PartyStakeLinkingsDocument } from './__generated__/PartyStakeLinkings';
|
||||||
|
|
||||||
export const useAddStake = (
|
export const useAddStake = (
|
||||||
address: string,
|
address: string,
|
||||||
|
@ -1,149 +0,0 @@
|
|||||||
import * as Types from '@vegaprotocol/types';
|
|
||||||
|
|
||||||
import { gql } from '@apollo/client';
|
|
||||||
import * as Apollo from '@apollo/client';
|
|
||||||
const defaultOptions = {} as const;
|
|
||||||
export type NodesFragmentFragment = {
|
|
||||||
__typename?: 'Node';
|
|
||||||
avatarUrl?: string | null;
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
pubkey: string;
|
|
||||||
stakedByOperator: string;
|
|
||||||
stakedByDelegates: string;
|
|
||||||
stakedTotal: string;
|
|
||||||
pendingStake: string;
|
|
||||||
rankingScore: {
|
|
||||||
__typename?: 'RankingScore';
|
|
||||||
rankingScore: string;
|
|
||||||
stakeScore: string;
|
|
||||||
performanceScore: string;
|
|
||||||
votingPower: string;
|
|
||||||
status: Types.ValidatorStatus;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export type NodesQueryVariables = Types.Exact<{ [key: string]: never }>;
|
|
||||||
|
|
||||||
export type NodesQuery = {
|
|
||||||
__typename?: 'Query';
|
|
||||||
epoch: {
|
|
||||||
__typename?: 'Epoch';
|
|
||||||
id: string;
|
|
||||||
timestamps: {
|
|
||||||
__typename?: 'EpochTimestamps';
|
|
||||||
start?: any | null;
|
|
||||||
end?: any | null;
|
|
||||||
expiry?: any | null;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
nodesConnection: {
|
|
||||||
__typename?: 'NodesConnection';
|
|
||||||
edges?: Array<{
|
|
||||||
__typename?: 'NodeEdge';
|
|
||||||
node: {
|
|
||||||
__typename?: 'Node';
|
|
||||||
avatarUrl?: string | null;
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
pubkey: string;
|
|
||||||
stakedByOperator: string;
|
|
||||||
stakedByDelegates: string;
|
|
||||||
stakedTotal: string;
|
|
||||||
pendingStake: string;
|
|
||||||
rankingScore: {
|
|
||||||
__typename?: 'RankingScore';
|
|
||||||
rankingScore: string;
|
|
||||||
stakeScore: string;
|
|
||||||
performanceScore: string;
|
|
||||||
votingPower: string;
|
|
||||||
status: Types.ValidatorStatus;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
} | null> | null;
|
|
||||||
};
|
|
||||||
nodeData?: { __typename?: 'NodeData'; stakedTotal: string } | null;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const NodesFragmentFragmentDoc = gql`
|
|
||||||
fragment NodesFragment on Node {
|
|
||||||
avatarUrl
|
|
||||||
id
|
|
||||||
name
|
|
||||||
pubkey
|
|
||||||
stakedByOperator
|
|
||||||
stakedByDelegates
|
|
||||||
stakedTotal
|
|
||||||
pendingStake
|
|
||||||
rankingScore {
|
|
||||||
rankingScore
|
|
||||||
stakeScore
|
|
||||||
performanceScore
|
|
||||||
votingPower
|
|
||||||
status
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
export const NodesDocument = gql`
|
|
||||||
query Nodes {
|
|
||||||
epoch {
|
|
||||||
id
|
|
||||||
timestamps {
|
|
||||||
start
|
|
||||||
end
|
|
||||||
expiry
|
|
||||||
}
|
|
||||||
}
|
|
||||||
nodesConnection {
|
|
||||||
edges {
|
|
||||||
node {
|
|
||||||
...NodesFragment
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
nodeData {
|
|
||||||
stakedTotal
|
|
||||||
}
|
|
||||||
}
|
|
||||||
${NodesFragmentFragmentDoc}
|
|
||||||
`;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* __useNodesQuery__
|
|
||||||
*
|
|
||||||
* To run a query within a React component, call `useNodesQuery` and pass it any options that fit your needs.
|
|
||||||
* When your component renders, `useNodesQuery` 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 } = useNodesQuery({
|
|
||||||
* variables: {
|
|
||||||
* },
|
|
||||||
* });
|
|
||||||
*/
|
|
||||||
export function useNodesQuery(
|
|
||||||
baseOptions?: Apollo.QueryHookOptions<NodesQuery, NodesQueryVariables>
|
|
||||||
) {
|
|
||||||
const options = { ...defaultOptions, ...baseOptions };
|
|
||||||
return Apollo.useQuery<NodesQuery, NodesQueryVariables>(
|
|
||||||
NodesDocument,
|
|
||||||
options
|
|
||||||
);
|
|
||||||
}
|
|
||||||
export function useNodesLazyQuery(
|
|
||||||
baseOptions?: Apollo.LazyQueryHookOptions<NodesQuery, NodesQueryVariables>
|
|
||||||
) {
|
|
||||||
const options = { ...defaultOptions, ...baseOptions };
|
|
||||||
return Apollo.useLazyQuery<NodesQuery, NodesQueryVariables>(
|
|
||||||
NodesDocument,
|
|
||||||
options
|
|
||||||
);
|
|
||||||
}
|
|
||||||
export type NodesQueryHookResult = ReturnType<typeof useNodesQuery>;
|
|
||||||
export type NodesLazyQueryHookResult = ReturnType<typeof useNodesLazyQuery>;
|
|
||||||
export type NodesQueryResult = Apollo.QueryResult<
|
|
||||||
NodesQuery,
|
|
||||||
NodesQueryVariables
|
|
||||||
>;
|
|
@ -1,36 +1,53 @@
|
|||||||
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||||
import { EpochCountdown } from '../../../components/epoch-countdown';
|
import { EpochCountdown } from '../../../components/epoch-countdown';
|
||||||
import { useNodesQuery } from './__generated___/Nodes';
|
import { useNodesQuery } from './__generated__/Nodes';
|
||||||
import { usePreviousEpochQuery } from '../__generated___/PreviousEpoch';
|
import { useStakingQuery } from '../__generated__/Staking';
|
||||||
|
import { usePreviousEpochQuery } from '../__generated__/PreviousEpoch';
|
||||||
import { ValidatorTables } from './validator-tables';
|
import { ValidatorTables } from './validator-tables';
|
||||||
import { useRefreshAfterEpoch } from '../../../hooks/use-refresh-after-epoch';
|
import { useRefreshAfterEpoch } from '../../../hooks/use-refresh-after-epoch';
|
||||||
|
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||||
|
|
||||||
export const EpochData = () => {
|
export const EpochData = () => {
|
||||||
// errorPolicy due to vegaprotocol/vega issue 5898
|
// errorPolicy due to vegaprotocol/vega issue 5898
|
||||||
const { data, error, loading, refetch } = useNodesQuery();
|
const { pubKey } = useVegaWallet();
|
||||||
|
const {
|
||||||
|
data: nodesData,
|
||||||
|
error: nodesError,
|
||||||
|
loading: nodesLoading,
|
||||||
|
refetch,
|
||||||
|
} = useNodesQuery();
|
||||||
|
const { data: userStakingData } = useStakingQuery({
|
||||||
|
variables: {
|
||||||
|
partyId: pubKey || '',
|
||||||
|
},
|
||||||
|
});
|
||||||
const { data: previousEpochData } = usePreviousEpochQuery({
|
const { data: previousEpochData } = usePreviousEpochQuery({
|
||||||
variables: {
|
variables: {
|
||||||
epochId: (Number(data?.epoch.id) - 1).toString(),
|
epochId: (Number(nodesData?.epoch.id) - 1).toString(),
|
||||||
},
|
},
|
||||||
skip: !data?.epoch.id,
|
skip: !nodesData?.epoch.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
useRefreshAfterEpoch(data?.epoch.timestamps.expiry, refetch);
|
useRefreshAfterEpoch(nodesData?.epoch.timestamps.expiry, refetch);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AsyncRenderer loading={loading} error={error} data={data}>
|
<AsyncRenderer loading={nodesLoading} error={nodesError} data={nodesData}>
|
||||||
{data?.epoch &&
|
{nodesData?.epoch &&
|
||||||
data.epoch.timestamps.start &&
|
nodesData.epoch.timestamps.start &&
|
||||||
data?.epoch.timestamps.expiry && (
|
nodesData?.epoch.timestamps.expiry && (
|
||||||
<div className="mb-10">
|
<div className="mb-10">
|
||||||
<EpochCountdown
|
<EpochCountdown
|
||||||
id={data.epoch.id}
|
id={nodesData.epoch.id}
|
||||||
startDate={new Date(data.epoch.timestamps.start)}
|
startDate={new Date(nodesData.epoch.timestamps.start)}
|
||||||
endDate={new Date(data.epoch.timestamps.expiry)}
|
endDate={new Date(nodesData.epoch.timestamps.expiry)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<ValidatorTables data={data} previousEpochData={previousEpochData} />
|
<ValidatorTables
|
||||||
|
nodesData={nodesData}
|
||||||
|
userStakingData={userStakingData}
|
||||||
|
previousEpochData={previousEpochData}
|
||||||
|
/>
|
||||||
</AsyncRenderer>
|
</AsyncRenderer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -3,14 +3,15 @@ import { act, fireEvent, render, screen } from '@testing-library/react';
|
|||||||
import { ConsensusValidatorsTable } from './consensus-validators-table';
|
import { ConsensusValidatorsTable } from './consensus-validators-table';
|
||||||
import { MockedProvider } from '@apollo/client/testing';
|
import { MockedProvider } from '@apollo/client/testing';
|
||||||
import { MemoryRouter } from 'react-router-dom';
|
import { MemoryRouter } from 'react-router-dom';
|
||||||
import { NodesDocument } from '../__generated___/Nodes';
|
import { NodesDocument } from '../__generated__/Nodes';
|
||||||
import { PreviousEpochDocument } from '../../__generated___/PreviousEpoch';
|
import { PreviousEpochDocument } from '../../__generated__/PreviousEpoch';
|
||||||
import * as Schema from '@vegaprotocol/types';
|
import * as Schema from '@vegaprotocol/types';
|
||||||
import { AppStateProvider } from '../../../../contexts/app-state/app-state-provider';
|
import { AppStateProvider } from '../../../../contexts/app-state/app-state-provider';
|
||||||
import type { MockedResponse } from '@apollo/client/testing';
|
import type { MockedResponse } from '@apollo/client/testing';
|
||||||
import type { PartialDeep } from 'type-fest';
|
import type { PartialDeep } from 'type-fest';
|
||||||
import type { NodesFragmentFragment } from '../__generated___/Nodes';
|
import type { NodesFragmentFragment } from '../__generated__/Nodes';
|
||||||
import type { PreviousEpochQuery } from '../../__generated___/PreviousEpoch';
|
import type { PreviousEpochQuery } from '../../__generated__/PreviousEpoch';
|
||||||
|
import type { ValidatorsView } from './validator-tables';
|
||||||
|
|
||||||
const nodeFactory = (
|
const nodeFactory = (
|
||||||
overrides?: PartialDeep<NodesFragmentFragment>
|
overrides?: PartialDeep<NodesFragmentFragment>
|
||||||
@ -142,7 +143,8 @@ const MOCK_TOTAL_STAKE = '28832590188747439203824';
|
|||||||
|
|
||||||
const renderValidatorsTable = (
|
const renderValidatorsTable = (
|
||||||
data = MOCK_NODES,
|
data = MOCK_NODES,
|
||||||
previousEpochData = MOCK_PREVIOUS_EPOCH
|
previousEpochData = MOCK_PREVIOUS_EPOCH,
|
||||||
|
validatorsView: ValidatorsView = 'all'
|
||||||
) => {
|
) => {
|
||||||
return render(
|
return render(
|
||||||
<AppStateProvider initialState={{ decimals: 18 }}>
|
<AppStateProvider initialState={{ decimals: 18 }}>
|
||||||
@ -152,6 +154,7 @@ const renderValidatorsTable = (
|
|||||||
data={data}
|
data={data}
|
||||||
previousEpochData={previousEpochData}
|
previousEpochData={previousEpochData}
|
||||||
totalStake={MOCK_TOTAL_STAKE}
|
totalStake={MOCK_TOTAL_STAKE}
|
||||||
|
validatorsView={validatorsView}
|
||||||
/>
|
/>
|
||||||
</MockedProvider>
|
</MockedProvider>
|
||||||
</MemoryRouter>
|
</MemoryRouter>
|
||||||
|
@ -19,7 +19,9 @@ import {
|
|||||||
import {
|
import {
|
||||||
defaultColDef,
|
defaultColDef,
|
||||||
NODE_LIST_GRID_STYLES,
|
NODE_LIST_GRID_STYLES,
|
||||||
|
PendingStakeRenderer,
|
||||||
stakedTotalPercentage,
|
stakedTotalPercentage,
|
||||||
|
StakeShareRenderer,
|
||||||
TotalPenaltiesRenderer,
|
TotalPenaltiesRenderer,
|
||||||
TotalStakeRenderer,
|
TotalStakeRenderer,
|
||||||
ValidatorFields,
|
ValidatorFields,
|
||||||
@ -54,6 +56,9 @@ interface CanonisedConsensusNodeProps {
|
|||||||
[ValidatorFields.OVERSTAKING_PENALTY]: string;
|
[ValidatorFields.OVERSTAKING_PENALTY]: string;
|
||||||
[ValidatorFields.TOTAL_PENALTIES]: string;
|
[ValidatorFields.TOTAL_PENALTIES]: string;
|
||||||
[ValidatorFields.PENDING_STAKE]: string;
|
[ValidatorFields.PENDING_STAKE]: string;
|
||||||
|
[ValidatorFields.STAKED_BY_USER]: string | undefined;
|
||||||
|
[ValidatorFields.PENDING_USER_STAKE]: string | undefined;
|
||||||
|
[ValidatorFields.USER_STAKE_SHARE]: string | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const getRowHeight = (params: RowHeightParams) => {
|
const getRowHeight = (params: RowHeightParams) => {
|
||||||
@ -61,7 +66,7 @@ const getRowHeight = (params: RowHeightParams) => {
|
|||||||
// Note: this value will change if the height of the top third cell renderer changes
|
// Note: this value will change if the height of the top third cell renderer changes
|
||||||
return 138;
|
return 138;
|
||||||
}
|
}
|
||||||
return 52;
|
return 68;
|
||||||
};
|
};
|
||||||
|
|
||||||
const TopThirdCellRenderer = (
|
const TopThirdCellRenderer = (
|
||||||
@ -117,6 +122,7 @@ export const ConsensusValidatorsTable = ({
|
|||||||
data,
|
data,
|
||||||
previousEpochData,
|
previousEpochData,
|
||||||
totalStake,
|
totalStake,
|
||||||
|
validatorsView,
|
||||||
}: ValidatorsTableProps) => {
|
}: ValidatorsTableProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const {
|
const {
|
||||||
@ -129,7 +135,7 @@ export const ConsensusValidatorsTable = ({
|
|||||||
|
|
||||||
const nodes = useMemo(() => {
|
const nodes = useMemo(() => {
|
||||||
if (!data || !previousEpochData) return [];
|
if (!data || !previousEpochData) return [];
|
||||||
const canonisedNodes = data
|
let canonisedNodes = data
|
||||||
.sort((a, b) => {
|
.sort((a, b) => {
|
||||||
const aVotingPower = new BigNumber(a.rankingScore.votingPower);
|
const aVotingPower = new BigNumber(a.rankingScore.votingPower);
|
||||||
const bVotingPower = new BigNumber(b.rankingScore.votingPower);
|
const bVotingPower = new BigNumber(b.rankingScore.votingPower);
|
||||||
@ -154,6 +160,9 @@ export const ConsensusValidatorsTable = ({
|
|||||||
rankingScore: { stakeScore, votingPower },
|
rankingScore: { stakeScore, votingPower },
|
||||||
pendingStake,
|
pendingStake,
|
||||||
votingPowerRanking,
|
votingPowerRanking,
|
||||||
|
stakedByUser,
|
||||||
|
pendingUserStake,
|
||||||
|
userStakeShare,
|
||||||
}) => {
|
}) => {
|
||||||
const { rawValidatorScore, performanceScore } =
|
const { rawValidatorScore, performanceScore } =
|
||||||
getLastEpochScoreAndPerformance(previousEpochData, id);
|
getLastEpochScoreAndPerformance(previousEpochData, id);
|
||||||
@ -201,12 +210,28 @@ export const ConsensusValidatorsTable = ({
|
|||||||
totalStake
|
totalStake
|
||||||
),
|
),
|
||||||
[ValidatorFields.PENDING_STAKE]: pendingStake,
|
[ValidatorFields.PENDING_STAKE]: pendingStake,
|
||||||
decimals,
|
[ValidatorFields.STAKED_BY_USER]: stakedByUser
|
||||||
|
? formatNumber(toBigNum(stakedByUser, decimals), 2)
|
||||||
|
: undefined,
|
||||||
|
[ValidatorFields.PENDING_USER_STAKE]: pendingUserStake,
|
||||||
|
[ValidatorFields.USER_STAKE_SHARE]: userStakeShare
|
||||||
|
? stakedTotalPercentage(userStakeShare)
|
||||||
|
: undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (canonisedNodes.length < 3 || !hideTopThird) {
|
if (validatorsView === 'myStake') {
|
||||||
|
canonisedNodes = canonisedNodes.filter(
|
||||||
|
(node) => node[ValidatorFields.STAKED_BY_USER] !== undefined
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
canonisedNodes.length < 3 ||
|
||||||
|
!hideTopThird ||
|
||||||
|
validatorsView === 'myStake'
|
||||||
|
) {
|
||||||
return canonisedNodes;
|
return canonisedNodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,7 +316,14 @@ export const ConsensusValidatorsTable = ({
|
|||||||
},
|
},
|
||||||
...remaining,
|
...remaining,
|
||||||
];
|
];
|
||||||
}, [data, decimals, hideTopThird, previousEpochData, totalStake]);
|
}, [
|
||||||
|
data,
|
||||||
|
decimals,
|
||||||
|
hideTopThird,
|
||||||
|
previousEpochData,
|
||||||
|
totalStake,
|
||||||
|
validatorsView,
|
||||||
|
]);
|
||||||
|
|
||||||
const ConsensusTable = forwardRef<AgGridReact>((_, gridRef) => {
|
const ConsensusTable = forwardRef<AgGridReact>((_, gridRef) => {
|
||||||
const colDefs = useMemo<ColDef[]>(
|
const colDefs = useMemo<ColDef[]>(
|
||||||
@ -311,7 +343,7 @@ export const ConsensusValidatorsTable = ({
|
|||||||
return a > b ? 1 : -1;
|
return a > b ? 1 : -1;
|
||||||
},
|
},
|
||||||
pinned: 'left',
|
pinned: 'left',
|
||||||
width: 240,
|
width: 260,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: ValidatorFields.STAKE,
|
field: ValidatorFields.STAKE,
|
||||||
@ -320,6 +352,20 @@ export const ConsensusValidatorsTable = ({
|
|||||||
cellRenderer: TotalStakeRenderer,
|
cellRenderer: TotalStakeRenderer,
|
||||||
width: 120,
|
width: 120,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
field: ValidatorFields.PENDING_STAKE,
|
||||||
|
headerName: t(ValidatorFields.PENDING_STAKE).toString(),
|
||||||
|
headerTooltip: t('PendingStakeDescription').toString(),
|
||||||
|
cellRenderer: PendingStakeRenderer,
|
||||||
|
width: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: ValidatorFields.STAKE_SHARE,
|
||||||
|
headerName: t(ValidatorFields.STAKE_SHARE).toString(),
|
||||||
|
headerTooltip: t('StakeShareDescription').toString(),
|
||||||
|
cellRenderer: StakeShareRenderer,
|
||||||
|
width: 120,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
field: ValidatorFields.NORMALISED_VOTING_POWER,
|
field: ValidatorFields.NORMALISED_VOTING_POWER,
|
||||||
headerName: t(ValidatorFields.NORMALISED_VOTING_POWER).toString(),
|
headerName: t(ValidatorFields.NORMALISED_VOTING_POWER).toString(),
|
||||||
@ -328,12 +374,6 @@ export const ConsensusValidatorsTable = ({
|
|||||||
width: 200,
|
width: 200,
|
||||||
sort: 'desc',
|
sort: 'desc',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
field: ValidatorFields.STAKE_SHARE,
|
|
||||||
headerName: t(ValidatorFields.STAKE_SHARE).toString(),
|
|
||||||
headerTooltip: t('StakeShareDescription').toString(),
|
|
||||||
width: 100,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
field: ValidatorFields.TOTAL_PENALTIES,
|
field: ValidatorFields.TOTAL_PENALTIES,
|
||||||
headerName: t(ValidatorFields.TOTAL_PENALTIES).toString(),
|
headerName: t(ValidatorFields.TOTAL_PENALTIES).toString(),
|
||||||
@ -341,14 +381,6 @@ export const ConsensusValidatorsTable = ({
|
|||||||
cellRenderer: TotalPenaltiesRenderer,
|
cellRenderer: TotalPenaltiesRenderer,
|
||||||
width: 120,
|
width: 120,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
field: ValidatorFields.PENDING_STAKE,
|
|
||||||
headerName: t(ValidatorFields.PENDING_STAKE).toString(),
|
|
||||||
headerTooltip: t('PendingStakeDescription').toString(),
|
|
||||||
valueFormatter: ({ value }) =>
|
|
||||||
formatNumber(toBigNum(value, decimals), 2),
|
|
||||||
width: 110,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
@ -1,70 +0,0 @@
|
|||||||
import {
|
|
||||||
getLastEpochScoreAndPerformance,
|
|
||||||
getTotalPenalties,
|
|
||||||
} from '../../shared';
|
|
||||||
import { stakedTotalPercentage } from './shared';
|
|
||||||
|
|
||||||
const MOCK_PREVIOUS_EPOCH = {
|
|
||||||
epoch: {
|
|
||||||
id: '1',
|
|
||||||
validatorsConnection: {
|
|
||||||
edges: [
|
|
||||||
{
|
|
||||||
node: {
|
|
||||||
id: '0x123',
|
|
||||||
rewardScore: {
|
|
||||||
rawValidatorScore: '0.25',
|
|
||||||
},
|
|
||||||
rankingScore: {
|
|
||||||
performanceScore: '0.75',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('stakedTotalPercentage', () => {
|
|
||||||
it('should return the correct percentage as a string, 2dp', () => {
|
|
||||||
expect(stakedTotalPercentage('1.2345')).toBe('123.45%');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('totalPenalties', () => {
|
|
||||||
it('should return the correct penalty based on arbitrary values, test 1', () => {
|
|
||||||
expect(
|
|
||||||
getTotalPenalties(
|
|
||||||
getLastEpochScoreAndPerformance(MOCK_PREVIOUS_EPOCH, '0x123')
|
|
||||||
.rawValidatorScore,
|
|
||||||
'0.1',
|
|
||||||
'5000',
|
|
||||||
'100000'
|
|
||||||
)
|
|
||||||
).toBe('50.00%');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return the correct penalty based on lower performance score than first test', () => {
|
|
||||||
expect(
|
|
||||||
getTotalPenalties(
|
|
||||||
getLastEpochScoreAndPerformance(MOCK_PREVIOUS_EPOCH, '0x123')
|
|
||||||
.rawValidatorScore,
|
|
||||||
'0.05',
|
|
||||||
'5000',
|
|
||||||
'100000'
|
|
||||||
)
|
|
||||||
).toBe('75.00%');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return the correct penalty based on higher amount of stake than other tests (great penalty due to anti-whaling)', () => {
|
|
||||||
expect(
|
|
||||||
getTotalPenalties(
|
|
||||||
getLastEpochScoreAndPerformance(MOCK_PREVIOUS_EPOCH, '0x123')
|
|
||||||
.rawValidatorScore,
|
|
||||||
'0.1',
|
|
||||||
'5000',
|
|
||||||
'5500'
|
|
||||||
)
|
|
||||||
).toBe('97.25%');
|
|
||||||
});
|
|
||||||
});
|
|
@ -10,9 +10,12 @@ import {
|
|||||||
Tooltip,
|
Tooltip,
|
||||||
TooltipCellComponent,
|
TooltipCellComponent,
|
||||||
} from '@vegaprotocol/ui-toolkit';
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
import type { NodesFragmentFragment } from '../__generated___/Nodes';
|
import { BigNumber } from '../../../../lib/bignumber';
|
||||||
import type { PreviousEpochQuery } from '../../__generated___/PreviousEpoch';
|
import type { NodesFragmentFragment } from '../__generated__/Nodes';
|
||||||
|
import type { PreviousEpochQuery } from '../../__generated__/PreviousEpoch';
|
||||||
import { useAppState } from '../../../../contexts/app-state/app-state-context';
|
import { useAppState } from '../../../../contexts/app-state/app-state-context';
|
||||||
|
import type { StakingDelegationFieldsFragment } from '../../__generated__/Staking';
|
||||||
|
import type { ValidatorsView } from './validator-tables';
|
||||||
|
|
||||||
export enum ValidatorFields {
|
export enum ValidatorFields {
|
||||||
RANKING_INDEX = 'rankingIndex',
|
RANKING_INDEX = 'rankingIndex',
|
||||||
@ -31,12 +34,49 @@ export enum ValidatorFields {
|
|||||||
PERFORMANCE_PENALTY = 'performancePenalty',
|
PERFORMANCE_PENALTY = 'performancePenalty',
|
||||||
OVERSTAKED_AMOUNT = 'overstakedAmount',
|
OVERSTAKED_AMOUNT = 'overstakedAmount',
|
||||||
OVERSTAKING_PENALTY = 'overstakingPenalty',
|
OVERSTAKING_PENALTY = 'overstakingPenalty',
|
||||||
|
// the following are additional fields added to the validator object displaying user data
|
||||||
|
STAKED_BY_USER = 'stakedByUser',
|
||||||
|
PENDING_USER_STAKE = 'pendingUserStake',
|
||||||
|
USER_STAKE_SHARE = 'userStakeShare',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const addUserDataToValidator = (
|
||||||
|
validator: NodesFragmentFragment,
|
||||||
|
currentEpochUserStaking: StakingDelegationFieldsFragment | undefined,
|
||||||
|
nextEpochUserStaking: StakingDelegationFieldsFragment | undefined,
|
||||||
|
currentUserStakeAvailable: string
|
||||||
|
) => {
|
||||||
|
return {
|
||||||
|
...validator,
|
||||||
|
[ValidatorFields.STAKED_BY_USER]:
|
||||||
|
currentEpochUserStaking && Number(currentEpochUserStaking?.amount) > 0
|
||||||
|
? currentEpochUserStaking.amount
|
||||||
|
: undefined,
|
||||||
|
[ValidatorFields.PENDING_USER_STAKE]: nextEpochUserStaking
|
||||||
|
? new BigNumber(nextEpochUserStaking?.amount)
|
||||||
|
.minus(new BigNumber(currentEpochUserStaking?.amount || 0))
|
||||||
|
.toString()
|
||||||
|
: undefined,
|
||||||
|
[ValidatorFields.USER_STAKE_SHARE]:
|
||||||
|
currentEpochUserStaking && Number(currentEpochUserStaking.amount) > 0
|
||||||
|
? new BigNumber(currentEpochUserStaking.amount).dividedBy(
|
||||||
|
new BigNumber(currentUserStakeAvailable)
|
||||||
|
)
|
||||||
|
: undefined,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ValidatorWithUserData = NodesFragmentFragment & {
|
||||||
|
stakedByUser?: string;
|
||||||
|
pendingUserStake?: string;
|
||||||
|
userStakeShare?: string;
|
||||||
|
};
|
||||||
|
|
||||||
export interface ValidatorsTableProps {
|
export interface ValidatorsTableProps {
|
||||||
data: NodesFragmentFragment[] | undefined;
|
data: ValidatorWithUserData[] | undefined;
|
||||||
previousEpochData: PreviousEpochQuery | undefined;
|
previousEpochData: PreviousEpochQuery | undefined;
|
||||||
totalStake: string;
|
totalStake: string;
|
||||||
|
validatorsView: ValidatorsView;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Custom styling to account for the scrollbar. This is needed because the
|
// Custom styling to account for the scrollbar. This is needed because the
|
||||||
@ -58,19 +98,23 @@ export const defaultColDef = {
|
|||||||
resizable: true,
|
resizable: true,
|
||||||
autoHeight: true,
|
autoHeight: true,
|
||||||
comparator: (a: string, b: string) => parseFloat(a) - parseFloat(b),
|
comparator: (a: string, b: string) => parseFloat(a) - parseFloat(b),
|
||||||
cellStyle: { margin: '10px 0', padding: '0 12px' },
|
|
||||||
tooltipComponent: TooltipCellComponent,
|
tooltipComponent: TooltipCellComponent,
|
||||||
|
cellStyle: { display: 'flex', alignItems: 'center', padding: '0 10px' },
|
||||||
};
|
};
|
||||||
|
|
||||||
interface ValidatorRendererProps {
|
interface ValidatorRendererProps {
|
||||||
data: { id: string; validator: { avatarUrl: string; name: string } };
|
data: {
|
||||||
|
id: string;
|
||||||
|
validator: { avatarUrl: string; name: string };
|
||||||
|
stakedByUser: string | undefined;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ValidatorRenderer = ({ data }: ValidatorRendererProps) => {
|
export const ValidatorRenderer = ({ data }: ValidatorRendererProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { avatarUrl, name } = data.validator;
|
const { avatarUrl, name } = data.validator;
|
||||||
return (
|
return (
|
||||||
<div className="grid grid-cols-[1fr_auto] gap-2 items-center">
|
<div className="w-[238px] grid grid-cols-[1fr_auto] gap-2 items-center">
|
||||||
<span className="flex overflow-hidden">
|
<span className="flex overflow-hidden">
|
||||||
{avatarUrl && (
|
{avatarUrl && (
|
||||||
<img
|
<img
|
||||||
@ -83,9 +127,19 @@ export const ValidatorRenderer = ({ data }: ValidatorRendererProps) => {
|
|||||||
<span>{name}</span>
|
<span>{name}</span>
|
||||||
</span>
|
</span>
|
||||||
<Link to={data.id}>
|
<Link to={data.id}>
|
||||||
<Button size="sm" fill={true}>
|
{data.stakedByUser ? (
|
||||||
|
<Button
|
||||||
|
data-testid="my-stake-btn"
|
||||||
|
size="sm"
|
||||||
|
className="text-vega-green border-vega-green"
|
||||||
|
>
|
||||||
|
{t('myStake')}
|
||||||
|
</Button>
|
||||||
|
) : (
|
||||||
|
<Button data-testid="stake-btn" size="sm" fill={true}>
|
||||||
{t('Stake')}
|
{t('Stake')}
|
||||||
</Button>
|
</Button>
|
||||||
|
)}
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -102,8 +156,14 @@ export const StakeNeededForPromotionRenderer = ({
|
|||||||
data,
|
data,
|
||||||
}: StakeNeededForPromotionRendererProps) => {
|
}: StakeNeededForPromotionRendererProps) => {
|
||||||
return (
|
return (
|
||||||
<Tooltip description={data.stakeNeededForPromotionDescription}>
|
<Tooltip
|
||||||
<span>
|
description={
|
||||||
|
<span data-testid="stake-needed-for-promotion-tooltip">
|
||||||
|
{data.stakeNeededForPromotionDescription}
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<span data-testid="stake-needed-for-promotion">
|
||||||
{data.stakeNeededForPromotion &&
|
{data.stakeNeededForPromotion &&
|
||||||
formatNumber(data.stakeNeededForPromotion, 2)}
|
formatNumber(data.stakeNeededForPromotion, 2)}
|
||||||
</span>
|
</span>
|
||||||
@ -134,7 +194,59 @@ export const VotingPowerRenderer = ({ data }: VotingPowerRendererProps) => {
|
|||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<span>{data.normalisedVotingPower}</span>
|
<span data-testid="normalised-voting-power">
|
||||||
|
{data.normalisedVotingPower}
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
interface PendingStakeRendererProps {
|
||||||
|
data: {
|
||||||
|
pendingStake: string;
|
||||||
|
pendingUserStake: string | undefined;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const PendingStakeRenderer = ({ data }: PendingStakeRendererProps) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const {
|
||||||
|
appState: { decimals },
|
||||||
|
} = useAppState();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Tooltip
|
||||||
|
description={
|
||||||
|
<>
|
||||||
|
<div data-testid="pending-stake-tooltip">
|
||||||
|
{t('pendingStake')}:{' '}
|
||||||
|
{formatNumber(toBigNum(data.pendingStake, decimals), decimals)}
|
||||||
|
</div>
|
||||||
|
{data.pendingUserStake && (
|
||||||
|
<div
|
||||||
|
className="text-vega-green border-t border-t-vega-dark-200 mt-1.5 pt-1"
|
||||||
|
data-testid="pending-user-stake-tooltip"
|
||||||
|
>
|
||||||
|
{t('myPendingStake')}:{' '}
|
||||||
|
{formatNumber(
|
||||||
|
toBigNum(data.pendingUserStake, decimals),
|
||||||
|
decimals
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div className="flex flex-col">
|
||||||
|
{data.pendingUserStake && data.pendingStake !== '0' && (
|
||||||
|
<span data-testid="pending-user-stake" className="text-vega-green">
|
||||||
|
{formatNumber(toBigNum(data.pendingUserStake, decimals), 2)}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
<span data-testid="total-pending-stake">
|
||||||
|
{formatNumber(toBigNum(data.pendingStake, decimals), 2)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -144,6 +256,7 @@ interface TotalStakeRendererProps {
|
|||||||
stake: string;
|
stake: string;
|
||||||
stakedByDelegates: string;
|
stakedByDelegates: string;
|
||||||
stakedByOperator: string;
|
stakedByOperator: string;
|
||||||
|
stakedByUser: string | undefined;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,18 +278,52 @@ export const TotalStakeRenderer = ({ data }: TotalStakeRendererProps) => {
|
|||||||
<div data-testid="staked-delegates-tooltip">
|
<div data-testid="staked-delegates-tooltip">
|
||||||
{t('stakedByDelegates')}: {data.stakedByDelegates.toString()}
|
{t('stakedByDelegates')}: {data.stakedByDelegates.toString()}
|
||||||
</div>
|
</div>
|
||||||
<div data-testid="total-staked-tooltip">
|
<div className="font-bold" data-testid="total-staked-tooltip">
|
||||||
{t('totalStake')}:{' '}
|
{t('totalStake')}: {formattedStake}
|
||||||
<span className="font-bold">{formattedStake}</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
{data.stakedByUser && (
|
||||||
|
<div
|
||||||
|
className="text-vega-green border-t border-t-vega-dark-200 mt-1.5 pt-1"
|
||||||
|
data-testid="staked-by-user-tooltip"
|
||||||
|
>
|
||||||
|
{t('stakedByMe')}: {data.stakedByUser}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<span>{formattedStake}</span>
|
<div className="flex flex-col">
|
||||||
|
{data.stakedByUser && (
|
||||||
|
<span data-testid="user-stake" className="text-vega-green">
|
||||||
|
{data.stakedByUser}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
<span data-testid="total-stake">{formattedStake}</span>
|
||||||
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
interface StakeShareRendererProps {
|
||||||
|
data: {
|
||||||
|
stakeShare: string;
|
||||||
|
userStakeShare: string | undefined;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const StakeShareRenderer = ({ data }: StakeShareRendererProps) => {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col">
|
||||||
|
{data.userStakeShare && (
|
||||||
|
<span data-testid="user-stake-share" className="text-vega-green">
|
||||||
|
{data.userStakeShare}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
<span data-testid="total-stake-share">{data.stakeShare}</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
interface TotalPenaltiesRendererProps {
|
interface TotalPenaltiesRendererProps {
|
||||||
data: {
|
data: {
|
||||||
performanceScore: string;
|
performanceScore: string;
|
||||||
@ -209,7 +356,7 @@ export const TotalPenaltiesRenderer = ({
|
|||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<span>{data.totalPenalties}</span>
|
<span data-testid="total-penalty">{data.totalPenalties}</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -21,6 +21,8 @@ import {
|
|||||||
ValidatorRenderer,
|
ValidatorRenderer,
|
||||||
TotalPenaltiesRenderer,
|
TotalPenaltiesRenderer,
|
||||||
TotalStakeRenderer,
|
TotalStakeRenderer,
|
||||||
|
StakeShareRenderer,
|
||||||
|
PendingStakeRenderer,
|
||||||
} from './shared';
|
} from './shared';
|
||||||
import type { AgGridReact } from 'ag-grid-react';
|
import type { AgGridReact } from 'ag-grid-react';
|
||||||
import type { ColDef } from 'ag-grid-community';
|
import type { ColDef } from 'ag-grid-community';
|
||||||
@ -38,6 +40,7 @@ export const StandbyPendingValidatorsTable = ({
|
|||||||
totalStake,
|
totalStake,
|
||||||
stakeNeededForPromotion,
|
stakeNeededForPromotion,
|
||||||
stakeNeededForPromotionDescription,
|
stakeNeededForPromotionDescription,
|
||||||
|
validatorsView,
|
||||||
}: StandbyPendingValidatorsTableProps) => {
|
}: StandbyPendingValidatorsTableProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const {
|
const {
|
||||||
@ -47,7 +50,7 @@ export const StandbyPendingValidatorsTable = ({
|
|||||||
|
|
||||||
const gridRef = useRef<AgGridReact | null>(null);
|
const gridRef = useRef<AgGridReact | null>(null);
|
||||||
|
|
||||||
const nodes = useMemo(() => {
|
let nodes = useMemo(() => {
|
||||||
if (!data) return [];
|
if (!data) return [];
|
||||||
|
|
||||||
return data
|
return data
|
||||||
@ -75,6 +78,9 @@ export const StandbyPendingValidatorsTable = ({
|
|||||||
rankingScore: { stakeScore },
|
rankingScore: { stakeScore },
|
||||||
pendingStake,
|
pendingStake,
|
||||||
votingPowerRanking,
|
votingPowerRanking,
|
||||||
|
stakedByUser,
|
||||||
|
pendingUserStake,
|
||||||
|
userStakeShare,
|
||||||
}) => {
|
}) => {
|
||||||
const { rawValidatorScore, performanceScore } =
|
const { rawValidatorScore, performanceScore } =
|
||||||
getLastEpochScoreAndPerformance(previousEpochData, id);
|
getLastEpochScoreAndPerformance(previousEpochData, id);
|
||||||
@ -152,6 +158,13 @@ export const StandbyPendingValidatorsTable = ({
|
|||||||
totalStake
|
totalStake
|
||||||
),
|
),
|
||||||
[ValidatorFields.PENDING_STAKE]: pendingStake,
|
[ValidatorFields.PENDING_STAKE]: pendingStake,
|
||||||
|
[ValidatorFields.STAKED_BY_USER]: stakedByUser
|
||||||
|
? formatNumber(toBigNum(stakedByUser, decimals), 2)
|
||||||
|
: undefined,
|
||||||
|
[ValidatorFields.PENDING_USER_STAKE]: pendingUserStake,
|
||||||
|
[ValidatorFields.USER_STAKE_SHARE]: userStakeShare
|
||||||
|
? stakedTotalPercentage(userStakeShare)
|
||||||
|
: undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -165,6 +178,12 @@ export const StandbyPendingValidatorsTable = ({
|
|||||||
totalStake,
|
totalStake,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
if (validatorsView === 'myStake') {
|
||||||
|
nodes = nodes.filter(
|
||||||
|
(node) => node[ValidatorFields.STAKED_BY_USER] !== undefined
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const StandbyPendingTable = forwardRef<AgGridReact>((_, gridRef) => {
|
const StandbyPendingTable = forwardRef<AgGridReact>((_, gridRef) => {
|
||||||
const colDefs = useMemo<ColDef[]>(
|
const colDefs = useMemo<ColDef[]>(
|
||||||
() => [
|
() => [
|
||||||
@ -180,7 +199,7 @@ export const StandbyPendingValidatorsTable = ({
|
|||||||
cellRenderer: ValidatorRenderer,
|
cellRenderer: ValidatorRenderer,
|
||||||
comparator: ({ name: a }, { name: b }) => Math.sign(a - b),
|
comparator: ({ name: a }, { name: b }) => Math.sign(a - b),
|
||||||
pinned: 'left',
|
pinned: 'left',
|
||||||
width: 240,
|
width: 260,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: ValidatorFields.STAKE,
|
field: ValidatorFields.STAKE,
|
||||||
@ -189,6 +208,20 @@ export const StandbyPendingValidatorsTable = ({
|
|||||||
cellRenderer: TotalStakeRenderer,
|
cellRenderer: TotalStakeRenderer,
|
||||||
width: 120,
|
width: 120,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
field: ValidatorFields.PENDING_STAKE,
|
||||||
|
headerName: t(ValidatorFields.PENDING_STAKE).toString(),
|
||||||
|
headerTooltip: t('PendingStakeDescription').toString(),
|
||||||
|
cellRenderer: PendingStakeRenderer,
|
||||||
|
width: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: ValidatorFields.STAKE_SHARE,
|
||||||
|
headerName: t(ValidatorFields.STAKE_SHARE).toString(),
|
||||||
|
headerTooltip: t('StakeShareDescription').toString(),
|
||||||
|
cellRenderer: StakeShareRenderer,
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
field: ValidatorFields.STAKE_NEEDED_FOR_PROMOTION,
|
field: ValidatorFields.STAKE_NEEDED_FOR_PROMOTION,
|
||||||
headerName: t(ValidatorFields.STAKE_NEEDED_FOR_PROMOTION).toString(),
|
headerName: t(ValidatorFields.STAKE_NEEDED_FOR_PROMOTION).toString(),
|
||||||
@ -199,12 +232,6 @@ export const StandbyPendingValidatorsTable = ({
|
|||||||
width: 210,
|
width: 210,
|
||||||
sort: 'asc',
|
sort: 'asc',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
field: ValidatorFields.STAKE_SHARE,
|
|
||||||
headerName: t(ValidatorFields.STAKE_SHARE).toString(),
|
|
||||||
headerTooltip: t('StakeShareDescription').toString(),
|
|
||||||
width: 100,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
field: ValidatorFields.TOTAL_PENALTIES,
|
field: ValidatorFields.TOTAL_PENALTIES,
|
||||||
headerName: t(ValidatorFields.TOTAL_PENALTIES).toString(),
|
headerName: t(ValidatorFields.TOTAL_PENALTIES).toString(),
|
||||||
@ -212,14 +239,6 @@ export const StandbyPendingValidatorsTable = ({
|
|||||||
cellRenderer: TotalPenaltiesRenderer,
|
cellRenderer: TotalPenaltiesRenderer,
|
||||||
width: 120,
|
width: 120,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
field: ValidatorFields.PENDING_STAKE,
|
|
||||||
headerName: t(ValidatorFields.PENDING_STAKE).toString(),
|
|
||||||
headerTooltip: t('PendingStakeDescription').toString(),
|
|
||||||
valueFormatter: ({ value }) =>
|
|
||||||
formatNumber(toBigNum(value, decimals), 2),
|
|
||||||
width: 110,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
@ -230,7 +249,7 @@ export const StandbyPendingValidatorsTable = ({
|
|||||||
domLayout="autoHeight"
|
domLayout="autoHeight"
|
||||||
style={{ width: '100%' }}
|
style={{ width: '100%' }}
|
||||||
customThemeParams={NODE_LIST_GRID_STYLES}
|
customThemeParams={NODE_LIST_GRID_STYLES}
|
||||||
rowHeight={52}
|
rowHeight={68}
|
||||||
defaultColDef={defaultColDef}
|
defaultColDef={defaultColDef}
|
||||||
tooltipShowDelay={0}
|
tooltipShowDelay={0}
|
||||||
animateRows={true}
|
animateRows={true}
|
||||||
|
@ -1,27 +1,30 @@
|
|||||||
import { useMemo } from 'react';
|
import { useMemo, useState } from 'react';
|
||||||
import { Trans, useTranslation } from 'react-i18next';
|
import { Trans, useTranslation } from 'react-i18next';
|
||||||
import { ConsensusValidatorsTable } from './consensus-validators-table';
|
import BigNumber from 'bignumber.js';
|
||||||
import { StandbyPendingValidatorsTable } from './standby-pending-validators-table';
|
|
||||||
import * as Schema from '@vegaprotocol/types';
|
import * as Schema from '@vegaprotocol/types';
|
||||||
import { formatNumber } from '../../../../lib/format-number';
|
|
||||||
import {
|
import {
|
||||||
createDocsLinks,
|
createDocsLinks,
|
||||||
removePaginationWrapper,
|
removePaginationWrapper,
|
||||||
toBigNum,
|
toBigNum,
|
||||||
} from '@vegaprotocol/utils';
|
} from '@vegaprotocol/utils';
|
||||||
import { Link as UTLink } from '@vegaprotocol/ui-toolkit';
|
|
||||||
import { SubHeading } from '../../../../components/heading';
|
|
||||||
import { useEnvironment } from '@vegaprotocol/environment';
|
import { useEnvironment } from '@vegaprotocol/environment';
|
||||||
|
import { Link as UTLink, Toggle } from '@vegaprotocol/ui-toolkit';
|
||||||
|
|
||||||
|
import { formatNumber } from '../../../../lib/format-number';
|
||||||
|
import { SubHeading } from '../../../../components/heading';
|
||||||
import { useAppState } from '../../../../contexts/app-state/app-state-context';
|
import { useAppState } from '../../../../contexts/app-state/app-state-context';
|
||||||
import type {
|
import { addUserDataToValidator } from './shared';
|
||||||
NodesQuery,
|
import { ConsensusValidatorsTable } from './consensus-validators-table';
|
||||||
NodesFragmentFragment,
|
import { StandbyPendingValidatorsTable } from './standby-pending-validators-table';
|
||||||
} from '../__generated___/Nodes';
|
import type { NodesQuery, NodesFragmentFragment } from '../__generated__/Nodes';
|
||||||
import type { PreviousEpochQuery } from '../../__generated___/PreviousEpoch';
|
import type { PreviousEpochQuery } from '../../__generated__/PreviousEpoch';
|
||||||
import BigNumber from 'bignumber.js';
|
import type { StakingQuery } from '../../__generated__/Staking';
|
||||||
|
import type { StakingDelegationFieldsFragment } from '../../__generated__/Staking';
|
||||||
|
import type { ValidatorWithUserData } from './shared';
|
||||||
|
|
||||||
export interface ValidatorsTableProps {
|
export interface ValidatorsTableProps {
|
||||||
data: NodesQuery | undefined;
|
nodesData: NodesQuery | undefined;
|
||||||
|
userStakingData: StakingQuery | undefined;
|
||||||
previousEpochData: PreviousEpochQuery | undefined;
|
previousEpochData: PreviousEpochQuery | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,8 +34,11 @@ interface SortedValidatorsProps {
|
|||||||
pendingValidators: NodesFragmentFragment[];
|
pendingValidators: NodesFragmentFragment[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ValidatorsView = 'all' | 'myStake';
|
||||||
|
|
||||||
export const ValidatorTables = ({
|
export const ValidatorTables = ({
|
||||||
data,
|
nodesData,
|
||||||
|
userStakingData,
|
||||||
previousEpochData,
|
previousEpochData,
|
||||||
}: ValidatorsTableProps) => {
|
}: ValidatorsTableProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -40,25 +46,69 @@ export const ValidatorTables = ({
|
|||||||
const {
|
const {
|
||||||
appState: { decimals },
|
appState: { decimals },
|
||||||
} = useAppState();
|
} = useAppState();
|
||||||
|
|
||||||
|
const [validatorsView, setValidatorsView] = useState<ValidatorsView>('all');
|
||||||
const totalStake = useMemo(
|
const totalStake = useMemo(
|
||||||
() => data?.nodeData?.stakedTotal || '0',
|
() => nodesData?.nodeData?.stakedTotal || '0',
|
||||||
[data?.nodeData?.stakedTotal]
|
[nodesData?.nodeData?.stakedTotal]
|
||||||
);
|
);
|
||||||
|
const epochId = useMemo(() => nodesData?.epoch.id, [nodesData?.epoch.id]);
|
||||||
|
const currentUserStakeAvailable = useMemo(
|
||||||
|
() => userStakingData?.party?.stakingSummary.currentStakeAvailable || '0',
|
||||||
|
[userStakingData?.party?.stakingSummary.currentStakeAvailable]
|
||||||
|
);
|
||||||
|
|
||||||
let stakeNeededForPromotion = undefined;
|
let stakeNeededForPromotion = undefined;
|
||||||
|
let delegations: StakingDelegationFieldsFragment[] | undefined = undefined;
|
||||||
|
|
||||||
|
if (userStakingData) {
|
||||||
|
delegations = removePaginationWrapper(
|
||||||
|
userStakingData?.party?.delegationsConnection?.edges
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const { consensusValidators, standbyValidators, pendingValidators } = useMemo(
|
const { consensusValidators, standbyValidators, pendingValidators } = useMemo(
|
||||||
() =>
|
() =>
|
||||||
removePaginationWrapper(data?.nodesConnection.edges).reduce(
|
removePaginationWrapper(nodesData?.nodesConnection.edges).reduce(
|
||||||
(acc: SortedValidatorsProps, validator) => {
|
(acc: SortedValidatorsProps, validator) => {
|
||||||
|
const validatorId = validator.id;
|
||||||
|
const currentDelegation = delegations?.find(
|
||||||
|
(d) => d.node.id === validatorId && d.epoch === Number(epochId)
|
||||||
|
);
|
||||||
|
const nextDelegation = delegations?.find(
|
||||||
|
(d) => d.node.id === validatorId && d.epoch === Number(epochId) + 1
|
||||||
|
);
|
||||||
|
|
||||||
switch (validator.rankingScore?.status) {
|
switch (validator.rankingScore?.status) {
|
||||||
case Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_TENDERMINT:
|
case Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_TENDERMINT:
|
||||||
acc.consensusValidators.push(validator);
|
acc.consensusValidators.push(
|
||||||
|
addUserDataToValidator(
|
||||||
|
validator,
|
||||||
|
currentDelegation,
|
||||||
|
nextDelegation,
|
||||||
|
currentUserStakeAvailable
|
||||||
|
)
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
case Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_ERSATZ:
|
case Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_ERSATZ:
|
||||||
acc.standbyValidators.push(validator);
|
acc.standbyValidators.push(
|
||||||
|
addUserDataToValidator(
|
||||||
|
validator,
|
||||||
|
currentDelegation,
|
||||||
|
nextDelegation,
|
||||||
|
currentUserStakeAvailable
|
||||||
|
)
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
case Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_PENDING:
|
case Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_PENDING:
|
||||||
acc.pendingValidators.push(validator);
|
acc.pendingValidators.push(
|
||||||
|
addUserDataToValidator(
|
||||||
|
validator,
|
||||||
|
currentDelegation,
|
||||||
|
nextDelegation,
|
||||||
|
currentUserStakeAvailable
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return acc;
|
return acc;
|
||||||
},
|
},
|
||||||
@ -68,7 +118,12 @@ export const ValidatorTables = ({
|
|||||||
pendingValidators: [],
|
pendingValidators: [],
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
[data?.nodesConnection.edges]
|
[
|
||||||
|
currentUserStakeAvailable,
|
||||||
|
delegations,
|
||||||
|
epochId,
|
||||||
|
nodesData?.nodesConnection.edges,
|
||||||
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@ -76,7 +131,7 @@ export const ValidatorTables = ({
|
|||||||
(standbyValidators.length || pendingValidators.length)
|
(standbyValidators.length || pendingValidators.length)
|
||||||
) {
|
) {
|
||||||
const lowestRankingConsensusScore = consensusValidators.reduce(
|
const lowestRankingConsensusScore = consensusValidators.reduce(
|
||||||
(lowest: NodesFragmentFragment, validator: NodesFragmentFragment) => {
|
(lowest: ValidatorWithUserData, validator: ValidatorWithUserData) => {
|
||||||
if (
|
if (
|
||||||
Number(validator.rankingScore.rankingScore) <
|
Number(validator.rankingScore.rankingScore) <
|
||||||
Number(lowest.rankingScore.rankingScore)
|
Number(lowest.rankingScore.rankingScore)
|
||||||
@ -98,19 +153,42 @@ export const ValidatorTables = ({
|
|||||||
).toString();
|
).toString();
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div data-testid="validator-tables">
|
<section data-testid="validator-tables">
|
||||||
|
<div className="grid w-full justify-end">
|
||||||
|
<div className="w-[400px]">
|
||||||
|
<Toggle
|
||||||
|
name="validators-view-toggle"
|
||||||
|
toggles={[
|
||||||
|
{
|
||||||
|
label: t('ALL VALIDATORS'),
|
||||||
|
value: 'all',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('STAKED BY ME'),
|
||||||
|
value: 'myStake',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
checkedValue={validatorsView}
|
||||||
|
onChange={(e) =>
|
||||||
|
setValidatorsView(e.target.value as ValidatorsView)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{consensusValidators.length > 0 && (
|
{consensusValidators.length > 0 && (
|
||||||
<>
|
<div className="mb-10">
|
||||||
<SubHeading title={t('status-tendermint')} />
|
<SubHeading title={t('status-tendermint')} />
|
||||||
<ConsensusValidatorsTable
|
<ConsensusValidatorsTable
|
||||||
data={consensusValidators}
|
data={consensusValidators}
|
||||||
previousEpochData={previousEpochData}
|
previousEpochData={previousEpochData}
|
||||||
totalStake={totalStake}
|
totalStake={totalStake}
|
||||||
|
validatorsView={validatorsView}
|
||||||
/>
|
/>
|
||||||
</>
|
</div>
|
||||||
)}
|
)}
|
||||||
{standbyValidators.length > 0 && (
|
{standbyValidators.length > 0 && (
|
||||||
<>
|
<div className="mb-10">
|
||||||
<SubHeading title={t('status-ersatz')} />
|
<SubHeading title={t('status-ersatz')} />
|
||||||
<p>
|
<p>
|
||||||
<Trans
|
<Trans
|
||||||
@ -126,8 +204,9 @@ export const ValidatorTables = ({
|
|||||||
totalStake={totalStake}
|
totalStake={totalStake}
|
||||||
stakeNeededForPromotion={stakeNeededForPromotion}
|
stakeNeededForPromotion={stakeNeededForPromotion}
|
||||||
stakeNeededForPromotionDescription="StakeNeededForPromotionStandbyDescription"
|
stakeNeededForPromotionDescription="StakeNeededForPromotionStandbyDescription"
|
||||||
|
validatorsView={validatorsView}
|
||||||
/>
|
/>
|
||||||
</>
|
</div>
|
||||||
)}
|
)}
|
||||||
{pendingValidators.length > 0 && (
|
{pendingValidators.length > 0 && (
|
||||||
<>
|
<>
|
||||||
@ -155,9 +234,10 @@ export const ValidatorTables = ({
|
|||||||
totalStake={totalStake}
|
totalStake={totalStake}
|
||||||
stakeNeededForPromotion={stakeNeededForPromotion}
|
stakeNeededForPromotion={stakeNeededForPromotion}
|
||||||
stakeNeededForPromotionDescription="StakeNeededForPromotionCandidateDescription"
|
stakeNeededForPromotionDescription="StakeNeededForPromotionCandidateDescription"
|
||||||
|
validatorsView={validatorsView}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</section>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -20,8 +20,8 @@ import NodeContainer from './nodes-container';
|
|||||||
import { useAppState } from '../../../contexts/app-state/app-state-context';
|
import { useAppState } from '../../../contexts/app-state/app-state-context';
|
||||||
import { Heading, SubHeading } from '../../../components/heading';
|
import { Heading, SubHeading } from '../../../components/heading';
|
||||||
import Routes from '../../routes';
|
import Routes from '../../routes';
|
||||||
import type { StakingQuery } from './__generated__/Staking';
|
import type { StakingQuery } from '../__generated__/Staking';
|
||||||
import type { PreviousEpochQuery } from '../__generated___/PreviousEpoch';
|
import type { PreviousEpochQuery } from '../__generated__/PreviousEpoch';
|
||||||
|
|
||||||
interface StakingNodeProps {
|
interface StakingNodeProps {
|
||||||
data?: StakingQuery;
|
data?: StakingQuery;
|
||||||
@ -116,13 +116,6 @@ export const StakingNode = ({ data, previousEpochData }: StakingNodeProps) => {
|
|||||||
t('validatorTitle', { nodeName: t('validatorTitleFallback') })
|
t('validatorTitle', { nodeName: t('validatorTitleFallback') })
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<section className="mb-4">
|
|
||||||
<ValidatorTable
|
|
||||||
node={nodeInfo}
|
|
||||||
stakedTotal={addDecimal(data?.nodeData?.stakedTotal || '0', decimals)}
|
|
||||||
previousEpochData={previousEpochData}
|
|
||||||
/>
|
|
||||||
</section>
|
|
||||||
{data?.epoch.timestamps.start && data?.epoch.timestamps.expiry && (
|
{data?.epoch.timestamps.start && data?.epoch.timestamps.expiry && (
|
||||||
<section className="mb-10">
|
<section className="mb-10">
|
||||||
<EpochCountdown
|
<EpochCountdown
|
||||||
@ -157,6 +150,13 @@ export const StakingNode = ({ data, previousEpochData }: StakingNodeProps) => {
|
|||||||
<ConnectToVega />
|
<ConnectToVega />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
<section className="mb-4">
|
||||||
|
<ValidatorTable
|
||||||
|
node={nodeInfo}
|
||||||
|
stakedTotal={addDecimal(data?.nodeData?.stakedTotal || '0', decimals)}
|
||||||
|
previousEpochData={previousEpochData}
|
||||||
|
/>
|
||||||
|
</section>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -4,11 +4,11 @@ import { useVegaWallet } from '@vegaprotocol/wallet';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useRefreshAfterEpoch } from '../../../hooks/use-refresh-after-epoch';
|
import { useRefreshAfterEpoch } from '../../../hooks/use-refresh-after-epoch';
|
||||||
import { SplashLoader } from '../../../components/splash-loader';
|
import { SplashLoader } from '../../../components/splash-loader';
|
||||||
import { useStakingQuery } from './__generated__/Staking';
|
import { useStakingQuery } from '../__generated__/Staking';
|
||||||
import { usePreviousEpochQuery } from '../__generated___/PreviousEpoch';
|
import { usePreviousEpochQuery } from '../__generated__/PreviousEpoch';
|
||||||
import type { ReactElement } from 'react';
|
import type { ReactElement } from 'react';
|
||||||
import type { StakingQuery } from './__generated__/Staking';
|
import type { StakingQuery } from '../__generated__/Staking';
|
||||||
import type { PreviousEpochQuery } from '../__generated___/PreviousEpoch';
|
import type { PreviousEpochQuery } from '../__generated__/PreviousEpoch';
|
||||||
|
|
||||||
// TODO should only request a single node. When migrating from deprecated APIs we should address this.
|
// TODO should only request a single node. When migrating from deprecated APIs we should address this.
|
||||||
|
|
||||||
|
@ -28,8 +28,8 @@ import {
|
|||||||
getStakePercentage,
|
getStakePercentage,
|
||||||
} from '../shared';
|
} from '../shared';
|
||||||
import type { ReactNode } from 'react';
|
import type { ReactNode } from 'react';
|
||||||
import type { StakingNodeFieldsFragment } from './__generated__/Staking';
|
import type { StakingNodeFieldsFragment } from '../__generated__/Staking';
|
||||||
import type { PreviousEpochQuery } from '../__generated___/PreviousEpoch';
|
import type { PreviousEpochQuery } from '../__generated__/PreviousEpoch';
|
||||||
|
|
||||||
const statuses = {
|
const statuses = {
|
||||||
[Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_ERSATZ]: 'status-ersatz',
|
[Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_ERSATZ]: 'status-ersatz',
|
||||||
@ -111,7 +111,7 @@ export const ValidatorTable = ({
|
|||||||
|
|
||||||
<div className="my-12" data-testid="validator-table">
|
<div className="my-12" data-testid="validator-table">
|
||||||
<SubHeading title={t('profile')} />
|
<SubHeading title={t('profile')} />
|
||||||
<RoundedWrapper>
|
<RoundedWrapper paddingBottom={true}>
|
||||||
<KeyValueTable data-testid="validator-table-profile">
|
<KeyValueTable data-testid="validator-table-profile">
|
||||||
<KeyValueTableRow>
|
<KeyValueTableRow>
|
||||||
<span>{t('id')}</span>
|
<span>{t('id')}</span>
|
||||||
@ -156,7 +156,7 @@ export const ValidatorTable = ({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<SubHeading title={t('ADDRESS')} />
|
<SubHeading title={t('ADDRESS')} />
|
||||||
<RoundedWrapper marginBottomLarge={true}>
|
<RoundedWrapper marginBottomLarge={true} paddingBottom={true}>
|
||||||
<KeyValueTable data-testid="validator-table-address">
|
<KeyValueTable data-testid="validator-table-address">
|
||||||
<KeyValueTableRow>
|
<KeyValueTableRow>
|
||||||
<span>{t('VEGA ADDRESS / PUBLIC KEY')}</span>
|
<span>{t('VEGA ADDRESS / PUBLIC KEY')}</span>
|
||||||
@ -187,7 +187,7 @@ export const ValidatorTable = ({
|
|||||||
</RoundedWrapper>
|
</RoundedWrapper>
|
||||||
|
|
||||||
<SubHeading title={t('STAKE')} />
|
<SubHeading title={t('STAKE')} />
|
||||||
<RoundedWrapper marginBottomLarge={true}>
|
<RoundedWrapper marginBottomLarge={true} paddingBottom={true}>
|
||||||
<KeyValueTable data-testid="validator-table-stake">
|
<KeyValueTable data-testid="validator-table-stake">
|
||||||
<KeyValueTableRow>
|
<KeyValueTableRow>
|
||||||
<span>{t('STAKED BY OPERATOR')}</span>
|
<span>{t('STAKED BY OPERATOR')}</span>
|
||||||
@ -238,7 +238,7 @@ export const ValidatorTable = ({
|
|||||||
</RoundedWrapper>
|
</RoundedWrapper>
|
||||||
|
|
||||||
<SubHeading title={t('PENALTIES')} />
|
<SubHeading title={t('PENALTIES')} />
|
||||||
<RoundedWrapper marginBottomLarge={true}>
|
<RoundedWrapper marginBottomLarge={true} paddingBottom={true}>
|
||||||
<KeyValueTable data-testid="validator-table-penalties">
|
<KeyValueTable data-testid="validator-table-penalties">
|
||||||
<KeyValueTableRow>
|
<KeyValueTableRow>
|
||||||
<span>{t('OVERSTAKED PENALTY')}</span>
|
<span>{t('OVERSTAKED PENALTY')}</span>
|
||||||
@ -270,7 +270,7 @@ export const ValidatorTable = ({
|
|||||||
</RoundedWrapper>
|
</RoundedWrapper>
|
||||||
|
|
||||||
<SubHeading title={t('VOTING POWER')} />
|
<SubHeading title={t('VOTING POWER')} />
|
||||||
<RoundedWrapper marginBottomLarge={true}>
|
<RoundedWrapper marginBottomLarge={true} paddingBottom={true}>
|
||||||
<KeyValueTable data-testid="validator-table-voting-power">
|
<KeyValueTable data-testid="validator-table-voting-power">
|
||||||
<KeyValueTableRow>
|
<KeyValueTableRow>
|
||||||
<span>{t('UNNORMALISED VOTING POWER')}</span>
|
<span>{t('UNNORMALISED VOTING POWER')}</span>
|
||||||
|
@ -23,7 +23,7 @@ export const YourStake = ({
|
|||||||
return (
|
return (
|
||||||
<div data-testid="your-stake">
|
<div data-testid="your-stake">
|
||||||
<SubHeading title={t('Your stake')} />
|
<SubHeading title={t('Your stake')} />
|
||||||
<RoundedWrapper>
|
<RoundedWrapper paddingBottom={true}>
|
||||||
<KeyValueTable>
|
<KeyValueTable>
|
||||||
<KeyValueTableRow>
|
<KeyValueTableRow>
|
||||||
{t('Your Stake On Node (This Epoch)')}
|
{t('Your Stake On Node (This Epoch)')}
|
||||||
|
@ -2,7 +2,7 @@ import {
|
|||||||
formatNumberPercentage,
|
formatNumberPercentage,
|
||||||
removePaginationWrapper,
|
removePaginationWrapper,
|
||||||
} from '@vegaprotocol/utils';
|
} from '@vegaprotocol/utils';
|
||||||
import type { PreviousEpochQuery } from './__generated___/PreviousEpoch';
|
import type { PreviousEpochQuery } from './__generated__/PreviousEpoch';
|
||||||
import { BigNumber } from '../../lib/bignumber';
|
import { BigNumber } from '../../lib/bignumber';
|
||||||
|
|
||||||
export const getLastEpochScoreAndPerformance = (
|
export const getLastEpochScoreAndPerformance = (
|
||||||
|
@ -1 +1 @@
|
|||||||
GRAPHQL_SCHEMA_PATH=https://api.n06.testnet.vega.xyz/graphql
|
GRAPHQL_SCHEMA_PATH=https://api.n07.testnet.vega.xyz/graphql
|
||||||
|
@ -88,6 +88,7 @@ export const DepositStatusMapping: {
|
|||||||
export const IntervalMapping: {
|
export const IntervalMapping: {
|
||||||
[T in Interval]: string;
|
[T in Interval]: string;
|
||||||
} = {
|
} = {
|
||||||
|
// @ts-ignore - temporarily suppressing this as it's a valid value
|
||||||
INTERVAL_BLOCK: '1 block',
|
INTERVAL_BLOCK: '1 block',
|
||||||
INTERVAL_I15M: 'I15M',
|
INTERVAL_I15M: 'I15M',
|
||||||
INTERVAL_I1D: 'I1D',
|
INTERVAL_I1D: 'I1D',
|
||||||
|
Loading…
Reference in New Issue
Block a user