fix(governance): penalties calculation (#3850)

This commit is contained in:
Art 2023-05-19 17:19:07 +02:00 committed by GitHub
parent fd338c7400
commit ff3519279d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 257 additions and 75 deletions

View File

@ -5,12 +5,22 @@ query PreviousEpoch($epochId: ID) {
edges { edges {
node { node {
id id
stakedTotal
rewardScore { rewardScore {
rawValidatorScore rawValidatorScore
performanceScore performanceScore
multisigScore
validatorScore
normalisedScore
validatorStatus
} }
rankingScore { rankingScore {
status
previousStatus
rankingScore
stakeScore stakeScore
performanceScore
votingPower
} }
} }
} }

View File

@ -8,7 +8,7 @@ export type PreviousEpochQueryVariables = Types.Exact<{
}>; }>;
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, performanceScore: string } | null, rankingScore: { __typename?: 'RankingScore', stakeScore: string } } } | null> | null } | null } }; export type PreviousEpochQuery = { __typename?: 'Query', epoch: { __typename?: 'Epoch', id: string, validatorsConnection?: { __typename?: 'NodesConnection', edges?: Array<{ __typename?: 'NodeEdge', node: { __typename?: 'Node', id: string, stakedTotal: string, rewardScore?: { __typename?: 'RewardScore', rawValidatorScore: string, performanceScore: string, multisigScore: string, validatorScore: string, normalisedScore: string, validatorStatus: Types.ValidatorStatus } | null, rankingScore: { __typename?: 'RankingScore', status: Types.ValidatorStatus, previousStatus: Types.ValidatorStatus, rankingScore: string, stakeScore: string, performanceScore: string, votingPower: string } } } | null> | null } | null } };
export const PreviousEpochDocument = gql` export const PreviousEpochDocument = gql`
@ -19,12 +19,22 @@ export const PreviousEpochDocument = gql`
edges { edges {
node { node {
id id
stakedTotal
rewardScore { rewardScore {
rawValidatorScore rawValidatorScore
performanceScore performanceScore
multisigScore
validatorScore
normalisedScore
validatorStatus
} }
rankingScore { rankingScore {
status
previousStatus
rankingScore
stakeScore stakeScore
performanceScore
votingPower
} }
} }
} }

View File

@ -79,36 +79,72 @@ const MOCK_PREVIOUS_EPOCH: PreviousEpochQuery = {
{ {
node: { node: {
id: 'ccc022b7e63a4d0a6d3a193c3940c88574060e58a184964c994998d86835a1b4', id: 'ccc022b7e63a4d0a6d3a193c3940c88574060e58a184964c994998d86835a1b4',
stakedTotal: '14182454495731682635157',
rewardScore: { rewardScore: {
rawValidatorScore: '0.25', rawValidatorScore: '0.25',
performanceScore: '0.9998677767864936', performanceScore: '0.9998677767864936',
multisigScore: '',
validatorScore: '',
normalisedScore: '',
validatorStatus:
Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_TENDERMINT,
}, },
rankingScore: { rankingScore: {
stakeScore: '0.2499583402766206', stakeScore: '0.2499583402766206',
performanceScore: '0.9998677767864936',
status: Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_TENDERMINT,
previousStatus:
Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_TENDERMINT,
rankingScore: '',
votingPower: '',
}, },
}, },
}, },
{ {
node: { node: {
id: '966438c6bffac737cfb08173ffcb3f393c4692b099ad80cb45a82e2dc0a8cf99', id: '966438c6bffac737cfb08173ffcb3f393c4692b099ad80cb45a82e2dc0a8cf99',
stakedTotal: '9618711883996159534058',
rewardScore: { rewardScore: {
rawValidatorScore: '0.3', rawValidatorScore: '0.3',
performanceScore: '1', performanceScore: '1',
multisigScore: '',
validatorScore: '0.31067',
normalisedScore: '',
validatorStatus:
Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_TENDERMINT,
}, },
rankingScore: { rankingScore: {
stakeScore: '0.25', stakeScore: '0.25',
performanceScore: '0.9998677767864936',
status: Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_TENDERMINT,
previousStatus:
Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_TENDERMINT,
rankingScore: '',
votingPower: '',
}, },
}, },
}, },
{ {
node: { node: {
id: '12c81b738e8051152e1afe44376ec37bca9216466e6d44cdd772194bad0ada81', id: '12c81b738e8051152e1afe44376ec37bca9216466e6d44cdd772194bad0ada81',
stakedTotal: '4041343338923442976709',
rewardScore: { rewardScore: {
rawValidatorScore: '0.35', rawValidatorScore: '0.35',
performanceScore: '0.999629748500531', performanceScore: '0.999629748500531',
multisigScore: '',
validatorScore: '',
normalisedScore: '',
validatorStatus:
Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_TENDERMINT,
}, },
rankingScore: { rankingScore: {
stakeScore: '0.2312', stakeScore: '0.2312',
performanceScore: '0.9998677767864936',
status: Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_TENDERMINT,
previousStatus:
Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_TENDERMINT,
rankingScore: '',
votingPower: '',
}, },
}, },
}, },

View File

@ -7,12 +7,12 @@ import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
import { useAppState } from '../../../../contexts/app-state/app-state-context'; import { useAppState } from '../../../../contexts/app-state/app-state-context';
import { BigNumber } from '../../../../lib/bignumber'; import { BigNumber } from '../../../../lib/bignumber';
import { import {
calculateOverallPenalty,
calculateOverstakedPenalty,
calculatesPerformancePenalty,
getFormattedPerformanceScore, getFormattedPerformanceScore,
getLastEpochScoreAndPerformance, getLastEpochScoreAndPerformance,
getNormalisedVotingPower, getNormalisedVotingPower,
getOverstakingPenalty,
getPerformancePenalty,
getTotalPenalties,
getUnnormalisedVotingPower, getUnnormalisedVotingPower,
} from '../../shared'; } from '../../shared';
import { import {
@ -32,6 +32,7 @@ import type { ValidatorsTableProps } from './shared';
import { import {
formatNumber, formatNumber,
formatNumberPercentage, formatNumberPercentage,
removePaginationWrapper,
toBigNum, toBigNum,
} from '@vegaprotocol/utils'; } from '@vegaprotocol/utils';
import { VALIDATOR_LOGO_MAP } from './logo-map'; import { VALIDATOR_LOGO_MAP } from './logo-map';
@ -136,6 +137,10 @@ export const ConsensusValidatorsTable = ({
[totalStake] [totalStake]
); );
const allNodesInPreviousEpoch = removePaginationWrapper(
previousEpochData?.epoch.validatorsConnection?.edges
);
const nodes = useMemo(() => { const nodes = useMemo(() => {
if (!data) return []; if (!data) return [];
let canonisedNodes = data let canonisedNodes = data
@ -160,7 +165,7 @@ export const ConsensusValidatorsTable = ({
stakedByDelegates, stakedByDelegates,
stakedByOperator, stakedByOperator,
stakedTotal, stakedTotal,
rankingScore: { stakeScore, votingPower }, rankingScore: { stakeScore, votingPower, performanceScore },
pendingStake, pendingStake,
stakedTotalRanking, stakedTotalRanking,
stakedByUser, stakedByUser,
@ -172,11 +177,8 @@ export const ConsensusValidatorsTable = ({
: avatarUrl : avatarUrl
? avatarUrl ? avatarUrl
: null; : null;
const { const { rawValidatorScore: previousEpochValidatorScore } =
rawValidatorScore: previousEpochValidatorScore, getLastEpochScoreAndPerformance(previousEpochData, id);
performanceScore: previousEpochPerformanceScore,
stakeScore: previousEpochStakeScore,
} = getLastEpochScoreAndPerformance(previousEpochData, id);
return { return {
id, id,
@ -199,21 +201,19 @@ export const ConsensusValidatorsTable = ({
toBigNum(stakedByOperator, decimals), toBigNum(stakedByOperator, decimals),
2 2
), ),
[ValidatorFields.PERFORMANCE_SCORE]: getFormattedPerformanceScore( [ValidatorFields.PERFORMANCE_SCORE]:
previousEpochPerformanceScore getFormattedPerformanceScore(performanceScore).toString(),
).toString(), [ValidatorFields.PERFORMANCE_PENALTY]: formatNumberPercentage(
[ValidatorFields.PERFORMANCE_PENALTY]: getPerformancePenalty( calculatesPerformancePenalty(performanceScore),
previousEpochPerformanceScore 2
), ),
[ValidatorFields.OVERSTAKING_PENALTY]: getOverstakingPenalty( [ValidatorFields.OVERSTAKING_PENALTY]: formatNumberPercentage(
previousEpochValidatorScore, calculateOverstakedPenalty(id, allNodesInPreviousEpoch),
previousEpochStakeScore 2
), ),
[ValidatorFields.TOTAL_PENALTIES]: getTotalPenalties( [ValidatorFields.TOTAL_PENALTIES]: formatNumberPercentage(
previousEpochValidatorScore, calculateOverallPenalty(id, allNodesInPreviousEpoch),
previousEpochPerformanceScore, 2
stakedTotal,
totalStake
), ),
[ValidatorFields.PENDING_STAKE]: pendingStake, [ValidatorFields.PENDING_STAKE]: pendingStake,
[ValidatorFields.STAKED_BY_USER]: stakedByUser [ValidatorFields.STAKED_BY_USER]: stakedByUser
@ -328,12 +328,12 @@ export const ConsensusValidatorsTable = ({
...remaining, ...remaining,
]; ];
}, [ }, [
allNodesInPreviousEpoch,
data, data,
decimals, decimals,
hideTopThird, hideTopThird,
previousEpochData, previousEpochData,
thirdOfTotalStake, thirdOfTotalStake,
totalStake,
validatorsView, validatorsView,
]); ]);

View File

@ -5,15 +5,14 @@ import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
import { useAppState } from '../../../../contexts/app-state/app-state-context'; import { useAppState } from '../../../../contexts/app-state/app-state-context';
import { BigNumber } from '../../../../lib/bignumber'; import { BigNumber } from '../../../../lib/bignumber';
import { import {
calculatesPerformancePenalty,
calculateOverallPenalty,
calculateOverstakedPenalty,
getFormattedPerformanceScore, getFormattedPerformanceScore,
getLastEpochScoreAndPerformance, getLastEpochScoreAndPerformance,
getOverstakingPenalty,
getPerformancePenalty,
getTotalPenalties,
} from '../../shared'; } from '../../shared';
import { import {
defaultColDef, defaultColDef,
StakeNeededForPromotionRenderer,
stakedTotalPercentage, stakedTotalPercentage,
ValidatorFields, ValidatorFields,
ValidatorRenderer, ValidatorRenderer,
@ -28,6 +27,7 @@ import type { ValidatorsTableProps } from './shared';
import { import {
formatNumber, formatNumber,
formatNumberPercentage, formatNumberPercentage,
removePaginationWrapper,
toBigNum, toBigNum,
} from '@vegaprotocol/utils'; } from '@vegaprotocol/utils';
@ -52,6 +52,10 @@ export const StandbyPendingValidatorsTable = ({
const gridRef = useRef<AgGridReact | null>(null); const gridRef = useRef<AgGridReact | null>(null);
const allNodesInPreviousEpoch = removePaginationWrapper(
previousEpochData?.epoch.validatorsConnection?.edges
);
let nodes = useMemo(() => { let nodes = useMemo(() => {
if (!data) return []; if (!data) return [];
@ -77,18 +81,15 @@ export const StandbyPendingValidatorsTable = ({
stakedByDelegates, stakedByDelegates,
stakedByOperator, stakedByOperator,
stakedTotal, stakedTotal,
rankingScore: { stakeScore }, rankingScore: { stakeScore, performanceScore },
pendingStake, pendingStake,
stakedTotalRanking, stakedTotalRanking,
stakedByUser, stakedByUser,
pendingUserStake, pendingUserStake,
userStakeShare, userStakeShare,
}) => { }) => {
const { const { performanceScore: previousEpochPerformanceScore } =
rawValidatorScore: previousEpochValidatorScore, getLastEpochScoreAndPerformance(previousEpochData, id);
performanceScore: previousEpochPerformanceScore,
stakeScore: previousEpochStakeScore,
} = getLastEpochScoreAndPerformance(previousEpochData, id);
let individualStakeNeededForPromotion, let individualStakeNeededForPromotion,
individualStakeNeededForPromotionDescription; individualStakeNeededForPromotionDescription;
@ -144,21 +145,19 @@ export const StandbyPendingValidatorsTable = ({
toBigNum(stakedByOperator, decimals), toBigNum(stakedByOperator, decimals),
2 2
), ),
[ValidatorFields.PERFORMANCE_SCORE]: getFormattedPerformanceScore( [ValidatorFields.PERFORMANCE_SCORE]:
previousEpochPerformanceScore getFormattedPerformanceScore(performanceScore).toString(),
).toString(), [ValidatorFields.PERFORMANCE_PENALTY]: formatNumberPercentage(
[ValidatorFields.PERFORMANCE_PENALTY]: getPerformancePenalty( calculatesPerformancePenalty(performanceScore),
previousEpochPerformanceScore 2
), ),
[ValidatorFields.OVERSTAKING_PENALTY]: getOverstakingPenalty( [ValidatorFields.OVERSTAKING_PENALTY]: formatNumberPercentage(
previousEpochValidatorScore, calculateOverstakedPenalty(id, allNodesInPreviousEpoch),
previousEpochStakeScore 2
), ),
[ValidatorFields.TOTAL_PENALTIES]: getTotalPenalties( [ValidatorFields.TOTAL_PENALTIES]: formatNumberPercentage(
previousEpochValidatorScore, calculateOverallPenalty(id, allNodesInPreviousEpoch),
previousEpochPerformanceScore, 2
stakedTotal,
totalStake
), ),
[ValidatorFields.PENDING_STAKE]: pendingStake, [ValidatorFields.PENDING_STAKE]: pendingStake,
[ValidatorFields.STAKED_BY_USER]: stakedByUser [ValidatorFields.STAKED_BY_USER]: stakedByUser
@ -172,13 +171,13 @@ export const StandbyPendingValidatorsTable = ({
} }
); );
}, [ }, [
allNodesInPreviousEpoch,
data, data,
decimals, decimals,
previousEpochData, previousEpochData,
stakeNeededForPromotion, stakeNeededForPromotion,
stakeNeededForPromotionDescription, stakeNeededForPromotionDescription,
t, t,
totalStake,
]); ]);
if (validatorsView === 'myStake') { if (validatorsView === 'myStake') {
@ -226,21 +225,21 @@ export const StandbyPendingValidatorsTable = ({
cellRenderer: StakeShareRenderer, cellRenderer: StakeShareRenderer,
width: 100, 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(),
headerTooltip: t(stakeNeededForPromotionDescription, { // headerTooltip: t(stakeNeededForPromotionDescription, {
prefix: t('The'), // prefix: t('The'),
}), // }),
cellRenderer: StakeNeededForPromotionRenderer, // cellRenderer: StakeNeededForPromotionRenderer,
width: 210, // width: 210,
}, // },
{ {
field: ValidatorFields.TOTAL_PENALTIES, field: ValidatorFields.TOTAL_PENALTIES,
headerName: t(ValidatorFields.TOTAL_PENALTIES).toString(), headerName: t(ValidatorFields.TOTAL_PENALTIES).toString(),
headerTooltip: t('TotalPenaltiesDescription').toString(), headerTooltip: t('TotalPenaltiesDescription').toString(),
cellRenderer: TotalPenaltiesRenderer, cellRenderer: TotalPenaltiesRenderer,
width: 120, width: 120 + 210,
}, },
], ],
[] []

View File

@ -1,11 +1,15 @@
import React, { useMemo } from 'react'; import { useMemo } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { import {
useEnvironment, useEnvironment,
DocsLinks, DocsLinks,
ExternalLinks, ExternalLinks,
} from '@vegaprotocol/environment'; } from '@vegaprotocol/environment';
import { toBigNum } from '@vegaprotocol/utils'; import {
formatNumberPercentage,
removePaginationWrapper,
toBigNum,
} from '@vegaprotocol/utils';
import * as Schema from '@vegaprotocol/types'; import * as Schema from '@vegaprotocol/types';
import { import {
Link as UTLink, Link as UTLink,
@ -24,11 +28,11 @@ import { SubHeading } from '../../../components/heading';
import { import {
getLastEpochScoreAndPerformance, getLastEpochScoreAndPerformance,
getNormalisedVotingPower, getNormalisedVotingPower,
getOverstakingPenalty,
getPerformancePenalty,
getTotalPenalties,
getUnnormalisedVotingPower, getUnnormalisedVotingPower,
getStakePercentage, getStakePercentage,
calculatesPerformancePenalty,
calculateOverstakedPenalty,
calculateOverallPenalty,
} 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';
@ -78,17 +82,27 @@ export const ValidatorTable = ({
const stakedOnNode = toBigNum(node.stakedTotal, decimals); const stakedOnNode = toBigNum(node.stakedTotal, decimals);
const { rawValidatorScore, performanceScore, stakeScore } = const { rawValidatorScore } = getLastEpochScoreAndPerformance(
getLastEpochScoreAndPerformance(previousEpochData, node.id); previousEpochData,
node.id
);
const stakePercentage = getStakePercentage(total, stakedOnNode); const stakePercentage = getStakePercentage(total, stakedOnNode);
const totalPenaltiesAmount = getTotalPenalties( const penalties = useMemo(() => {
rawValidatorScore, const allNodesInPreviousEpoch = removePaginationWrapper(
performanceScore, previousEpochData?.epoch.validatorsConnection?.edges
stakedOnNode.toString(),
total.toString()
); );
return {
// current epoch
performance: calculatesPerformancePenalty(
node.rankingScore.performanceScore
),
// previous epoch
overstaked: calculateOverstakedPenalty(node.id, allNodesInPreviousEpoch),
overall: calculateOverallPenalty(node.id, allNodesInPreviousEpoch),
};
}, [node, previousEpochData?.epoch.validatorsConnection?.edges]);
return ( return (
<> <>
@ -242,7 +256,7 @@ export const ValidatorTable = ({
<Tooltip description={t('OverstakedPenaltyDescription')}> <Tooltip description={t('OverstakedPenaltyDescription')}>
<span data-testid="overstaking-penalty"> <span data-testid="overstaking-penalty">
{getOverstakingPenalty(rawValidatorScore, stakeScore)} {formatNumberPercentage(penalties.overstaked, 2)}
</span> </span>
</Tooltip> </Tooltip>
</KeyValueTableRow> </KeyValueTableRow>
@ -251,7 +265,7 @@ export const ValidatorTable = ({
<Tooltip description={t('PerformancePenaltyDescription')}> <Tooltip description={t('PerformancePenaltyDescription')}>
<span data-testid="performance-penalty"> <span data-testid="performance-penalty">
{getPerformancePenalty(performanceScore)} {formatNumberPercentage(penalties.performance, 2)}
</span> </span>
</Tooltip> </Tooltip>
</KeyValueTableRow> </KeyValueTableRow>
@ -260,7 +274,7 @@ export const ValidatorTable = ({
<strong>{t('TOTAL PENALTIES')}</strong> <strong>{t('TOTAL PENALTIES')}</strong>
</span> </span>
<span data-testid="total-penalties"> <span data-testid="total-penalties">
<strong>{totalPenaltiesAmount}</strong> <strong>{formatNumberPercentage(penalties.overall, 2)}</strong>
</span> </span>
</KeyValueTableRow> </KeyValueTableRow>
</KeyValueTable> </KeyValueTable>

View File

@ -9,6 +9,7 @@ import {
getTotalPenalties, getTotalPenalties,
getStakePercentage, getStakePercentage,
} from './shared'; } from './shared';
import * as Schema from '@vegaprotocol/types';
describe('getLastEpochScoreAndPerformance', () => { describe('getLastEpochScoreAndPerformance', () => {
const mockPreviousEpochData = { const mockPreviousEpochData = {
@ -19,24 +20,48 @@ describe('getLastEpochScoreAndPerformance', () => {
{ {
node: { node: {
id: '0x123', id: '0x123',
stakedTotal: '',
rewardScore: { rewardScore: {
rawValidatorScore: '0.25', rawValidatorScore: '0.25',
performanceScore: '0.75', performanceScore: '0.75',
multisigScore: '',
validatorScore: '',
normalisedScore: '',
validatorStatus:
Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_TENDERMINT,
}, },
rankingScore: { rankingScore: {
stakeScore: '0.25', stakeScore: '0.25',
performanceScore: '0.75',
status: Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_TENDERMINT,
previousStatus:
Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_TENDERMINT,
rankingScore: '',
votingPower: '',
}, },
}, },
}, },
{ {
node: { node: {
id: '0x234', id: '0x234',
stakedTotal: '',
rewardScore: { rewardScore: {
rawValidatorScore: '0.35', rawValidatorScore: '0.35',
performanceScore: '0.85', performanceScore: '0.85',
multisigScore: '',
validatorScore: '',
normalisedScore: '',
validatorStatus:
Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_TENDERMINT,
}, },
rankingScore: { rankingScore: {
stakeScore: '0.25', stakeScore: '0.25',
performanceScore: '0.85',
status: Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_TENDERMINT,
previousStatus:
Schema.ValidatorStatus.VALIDATOR_NODE_STATUS_TENDERMINT,
rankingScore: '',
votingPower: '',
}, },
}, },
}, },

View File

@ -4,6 +4,94 @@ import {
} 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';
import type { LastArrayElement } from 'type-fest';
type Node = NonNullable<
LastArrayElement<
NonNullable<
NonNullable<PreviousEpochQuery['epoch']['validatorsConnection']>['edges']
>
>
>['node'];
/**
* Calculates theoretical stake score for a given node
* @param nodeId Id of a node for which a score is calculated
* @param nodes A collection of all nodes
* @returns Theoretical stake score for given node based on the staked total
* of all node of the same type (status)
*/
const calculateTheoreticalStakeScore = (nodeId: string, nodes: Node[]) => {
const node = nodes.find((n) => n.id === nodeId);
if (!node) {
return new BigNumber(0);
}
const all = nodes
.filter((n) => n.rankingScore.status === node.rankingScore.status)
.map((n) => new BigNumber(n.stakedTotal));
const sumOfSameType = all.reduce((acc, a) => acc.plus(a), new BigNumber(0));
if (sumOfSameType.isZero()) {
return new BigNumber(0);
}
return new BigNumber(node.stakedTotal).dividedBy(sumOfSameType);
};
/**
* Calculates overall penalty for a given node
* @param nodeId Id of a node for which a penalty is calculated
* @param nodes A collection of all nodes - needed to calculate theoretical stake score
* @returns %
*/
export const calculateOverallPenalty = (nodeId: string, nodes: Node[]) => {
const node = nodes.find((n) => n.id === nodeId);
const tts = calculateTheoreticalStakeScore(nodeId, nodes);
if (!node || tts.isZero()) {
return new BigNumber(0);
}
const penalty = new BigNumber(1)
.minus(new BigNumber(node.rewardScore?.validatorScore || 0).dividedBy(tts))
.times(100);
return penalty.isLessThan(0) ? new BigNumber(0) : penalty;
};
/**
* Calculates over-staked penalty for a given node
* @param nodeId Id of a node for which a penalty is calculated
* @param nodes A collection of all nodes - needed to calculate theoretical stake score
* @returns %
*/
export const calculateOverstakedPenalty = (nodeId: string, nodes: Node[]) => {
const node = nodes.find((n) => n.id === nodeId);
const tts = calculateTheoreticalStakeScore(nodeId, nodes);
if (!node || tts.isZero()) {
return new BigNumber(0);
}
const penalty = new BigNumber(1)
.minus(
new BigNumber(node.rewardScore?.rawValidatorScore || 0).dividedBy(tts)
)
.times(100);
console.log(
nodeId,
new BigNumber(node.rewardScore?.rawValidatorScore || 0).toString(),
tts.toString(),
new BigNumber(node.rewardScore?.rawValidatorScore || 0)
.dividedBy(tts)
.toString()
);
return penalty.isLessThan(0) ? new BigNumber(0) : penalty;
};
/**
* Calculates performance penalty based on the given performance score.
* @returns %
*/
export const calculatesPerformancePenalty = (performanceScore: string) => {
const penalty = new BigNumber(1)
.minus(new BigNumber(performanceScore))
.times(100);
return penalty.isLessThan(0) ? new BigNumber(0) : penalty;
};
export const getLastEpochScoreAndPerformance = ( export const getLastEpochScoreAndPerformance = (
previousEpochData: PreviousEpochQuery | undefined, previousEpochData: PreviousEpochQuery | undefined,
@ -15,7 +103,7 @@ export const getLastEpochScoreAndPerformance = (
return { return {
rawValidatorScore: validator?.rewardScore?.rawValidatorScore, rawValidatorScore: validator?.rewardScore?.rawValidatorScore,
performanceScore: validator?.rewardScore?.performanceScore, performanceScore: validator?.rankingScore?.performanceScore,
stakeScore: validator?.rankingScore?.stakeScore, stakeScore: validator?.rankingScore?.stakeScore,
}; };
}; };