Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

506/vp #561

Merged
merged 6 commits into from
Nov 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
- Add `feegrant` and `authz` messages ([\#481](https://github.com/forbole/big-dipper-2.0-cosmos/issues/481))
- Add `vesting` messages ([\#538](https://github.com/forbole/big-dipper-2.0-cosmos/issues/538))
- Add status row in `/validators` ([\#556](https://github.com/forbole/big-dipper-2.0-cosmos/issues/556))
- Show who the top 34% validators are ([\#506](https://github.com/forbole/big-dipper-2.0-cosmos/issues/506))
## Bug fixes
- Fix validator searchbar ([\#540](https://github.com/forbole/big-dipper-2.0-cosmos/issues/540))

Expand Down
3 changes: 2 additions & 1 deletion public/locales/en/validators.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,6 @@
"missedBlockCounter": "Missed Block Counter: {{amount}}",
"signedBlockWindow": "Signed Block Window: {{amount}}",
"lastSeen": "Last Seen",
"status": "Status"
"status": "Status",
"votingPowerExplanation": "As the top 34% voting power can easily <0>decrease network security</0> and <0>halt the network</0> they will be highlighted differently in order to educate and encourage decentralization"
}
1 change: 1 addition & 0 deletions src/components/info_popover/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const InfoPopover: React.FC<{
aria-haspopup="true"
onMouseEnter={handlePopoverOpen}
onMouseLeave={handlePopoverClose}
className={classes.root}
>
{display || (
<HelpOutline
Expand Down
4 changes: 4 additions & 0 deletions src/components/info_popover/styles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ export const useStyles = () => {
const styles = makeStyles(
(theme) => {
return ({
root: {
display: 'flex',
alignItems: 'center',
},
icon: {
display: 'inline-block',
fontSize: '1rem',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@ import { useGrid } from '@hooks';
import {
SortArrows,
AvatarName,
InfoPopover,
} from '@components';
import { getValidatorConditionClass } from '@utils/get_validator_condition';
import { getValidatorStatus } from '@utils/get_validator_status';
import { useStyles } from './styles';
import { fetchColumns } from './utils';
import { ItemType } from '../../types';
import {
Condition, VotingPower,
Condition,
VotingPower,
VotingPowerExplanation,
} from '..';

const Desktop: React.FC<{
Expand Down Expand Up @@ -63,6 +66,7 @@ const Desktop: React.FC<{
percentDisplay={percentDisplay}
percentage={x.votingPowerPercent}
content={votingPower}
topVotingPower={x.topVotingPower}
/>
),
status: (
Expand Down Expand Up @@ -104,6 +108,26 @@ const Desktop: React.FC<{
sortKey: sortingKey,
} = columns[columnIndex];

let formattedComponent = component;

if (key === 'votingPower') {
formattedComponent = (
<Typography variant="h4" className="label popover">
{t('votingPower')}
<InfoPopover
content={<VotingPowerExplanation />}
/>
{!!sort && (
<SortArrows
sort={props.sortKey === sortingKey
? props.sortDirection
: undefined}
/>
)}
</Typography>
);
}

return (
<div
style={style}
Expand All @@ -118,7 +142,7 @@ const Desktop: React.FC<{
onClick={() => (sort ? props.handleSort(sortingKey) : null)}
role="button"
>
{component || (
{formattedComponent || (
<Typography
variant="h4"
align={align}
Expand Down
2 changes: 2 additions & 0 deletions src/screens/validators/components/list/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import Mobile from './mobile';
import Tabs from './tabs';
import Condition from './condition';
import VotingPower from './voting_power';
import VotingPowerExplanation from './voting_power_explanation';

export {
Desktop,
Mobile,
Tabs,
Condition,
VotingPower,
VotingPowerExplanation,
};
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ const Mobile: React.FC<{
percentDisplay={percentDisplay}
percentage={x.votingPowerPercent}
content={votingPower}
topVotingPower={x.topVotingPower}
/>
),
status,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ const VotingPower: React.FC<{
percentage: number;
percentDisplay: string;
content: string;
topVotingPower: boolean;
}> = ({
className, percentage, content, percentDisplay,
className, percentage, content, percentDisplay, topVotingPower,
}) => {
const classes = useStyles(percentage);
const classes = useStyles(percentage, topVotingPower);
return (
<div className={classnames(className, classes.root)}>
<div className={classes.content}>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,33 +1,49 @@
import { makeStyles } from '@material-ui/core/styles';
import Color from 'color';

export const useStyles = (percentage: number) => {
export const useStyles = (percentage: number, topVotingPower:boolean) => {
const styles = makeStyles(
(theme) => {
return ({
root: {
'& .MuiTypography-body1': {
color: theme.palette.custom.fonts.fontTwo,
color: (
topVotingPower
? theme.palette.custom.fonts.fontFour
: theme.palette.custom.fonts.fontTwo
),
},
},
chart: {
display: 'flex',
height: '2px',
borderRadius: theme.shape.borderRadius,
background: Color(theme.palette.custom.primaryData.three).alpha(0.2).string(),
background: (
topVotingPower
? Color(theme.palette.custom.fonts.fontFour).alpha(0.2).string()
: Color(theme.palette.custom.primaryData.three).alpha(0.2).string()
),
overflow: 'hidden',
},
active: {
width: `${percentage}%`,
background: theme.palette.custom.primaryData.three,
background: (
topVotingPower
? theme.palette.custom.fonts.fontFour
: theme.palette.custom.primaryData.three
),
},
content: {
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
marginBottom: theme.spacing(1),
'& .percentage': {
color: theme.palette.custom.primaryData.three,
color: (
topVotingPower
? theme.palette.custom.fonts.fontFour
: theme.palette.custom.primaryData.three
),
},
[theme.breakpoints.up('lg')]: {
marginBottom: 0,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from 'react';
import Trans from 'next-translate/Trans';
import { Typography } from '@material-ui/core';
import { useStyles } from './styles';

const VotingPowerExplanation = () => {
const classes = useStyles();

return (
<div className={classes.root}>
<Typography>
<Trans
i18nKey="validators:votingPowerExplanation"
components={[
<b />,
]}
/>
</Typography>
</div>
);
};

export default VotingPowerExplanation;
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { makeStyles } from '@material-ui/core/styles';

export const useStyles = () => {
const styles = makeStyles(
() => {
return ({
root: {
height: '100%',
},
});
},
)();

return styles;
};
29 changes: 27 additions & 2 deletions src/screens/validators/components/list/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useState } from 'react';
import Big from 'big.js';
import * as R from 'ramda';
import numeral from 'numeral';
import {
Expand All @@ -12,7 +13,9 @@ import {
SlashingParams,
} from '@models';
import {
ValidatorsState, ItemType,
ValidatorsState,
ItemType,
ValidatorType,
} from './types';

export const useValidators = () => {
Expand Down Expand Up @@ -56,7 +59,7 @@ export const useValidators = () => {

const { signedBlockWindow } = slashingParams;

const formattedItems = data.validator.filter((x) => x.validatorInfo).map((x) => {
let formattedItems: ValidatorType[] = data.validator.filter((x) => x.validatorInfo).map((x) => {
const votingPower = R.pathOr(0, ['validatorVotingPowers', 0, 'votingPower'], x);
const votingPowerPercent = numeral((votingPower / votingPowerOverall) * 100).value();
const totalDelegations = x.delegations.reduce((a, b) => {
Expand Down Expand Up @@ -88,6 +91,28 @@ export const useValidators = () => {
});
});

// get the top 34% validators
formattedItems = formattedItems.filter((x) => x.status === 3).sort((a, b) => {
return a.votingPower > b.votingPower ? -1 : 1;
});

// add key to indicate they are part of top 34%
let cumulativeVotingPower = Big(0);
let reached = false;
formattedItems.forEach((x) => {
const totalVp = cumulativeVotingPower.add(x.votingPowerPercent);
if (totalVp.lte(34) && !reached) {
x.topVotingPower = true;
}

if (totalVp.gt(34) && !reached) {
x.topVotingPower = true;
reached = true;
}

cumulativeVotingPower = totalVp;
});

return {
votingPowerOverall,
items: formattedItems,
Expand Down
1 change: 1 addition & 0 deletions src/screens/validators/components/list/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export type ValidatorType = {
status: number;
jailed: boolean;
delegators: number;
topVotingPower?: boolean; // top 34% VP
}

export type ValidatorsState = {
Expand Down