Bug fix/ne snag list (#1741)

* use uncapped saturation

* display uncapped saturation

update profit margin tooltip

update operating cost

update rewards tooltip

update stake saturation tooltip

update reward tooltips

update profit margin tooltip

* allow full gateway field to be clickable

use uncapped saturation on mixnode details page
This commit is contained in:
Fouad
2022-11-09 12:39:14 +00:00
committed by GitHub
parent 62e9c8236a
commit baa61c07d5
12 changed files with 53 additions and 41 deletions
+2
View File
@@ -41,6 +41,8 @@ pub(crate) async fn retrieve_mixnode_econ_stats(
Some(EconomicDynamicsStats {
stake_saturation: best_effort_small_dec_to_f64(stake_saturation.saturation) as f32,
uncapped_saturation: best_effort_small_dec_to_f64(stake_saturation.uncapped_saturation)
as f32,
active_set_inclusion_probability: inclusion_probability.in_active,
reserve_set_inclusion_probability: inclusion_probability.in_reserve,
// drop precision for compatibility sake
+2
View File
@@ -34,6 +34,7 @@ pub(crate) struct PrettyDetailedMixNodeBond {
pub layer: Layer,
pub mix_node: MixNode,
pub stake_saturation: f32,
pub uncapped_saturation: f32,
pub avg_uptime: u8,
pub estimated_operator_apy: f64,
pub estimated_delegators_apy: f64,
@@ -153,6 +154,7 @@ pub(crate) struct NodeStats {
#[derive(Clone, Serialize, Deserialize, JsonSchema)]
pub(crate) struct EconomicDynamicsStats {
pub(crate) stake_saturation: f32,
pub(crate) uncapped_saturation: f32,
pub(crate) active_set_inclusion_probability: SelectionChance,
pub(crate) reserve_set_inclusion_probability: SelectionChance,
+2
View File
@@ -151,6 +151,8 @@ impl ThreadsafeMixNodesCache {
mix_node: node.mixnode_details.bond_information.mix_node.clone(),
avg_uptime: node.performance.round_to_integer(),
stake_saturation: best_effort_small_dec_to_f64(node.stake_saturation) as f32,
uncapped_saturation: best_effort_small_dec_to_f64(node.uncapped_stake_saturation)
as f32,
estimated_operator_apy: best_effort_small_dec_to_f64(node.estimated_operator_apy),
estimated_delegators_apy: best_effort_small_dec_to_f64(node.estimated_delegators_apy),
operating_cost: rewarding_info.cost_params.interval_operating_cost.clone(),
@@ -6,14 +6,16 @@ export const EconomicsInfoColumns: ColumnsType[] = [
title: 'Estimated Total Reward',
flex: 1,
headerAlign: 'left',
tooltipInfo: 'Estimated reward per epoch for this profit margin if your node is selected in the active set.',
tooltipInfo:
'Estimated node reward (total for the operator and delegators) in the current epoch. There are roughly 24 epochs in a day.',
},
{
field: 'estimatedOperatorReward',
title: 'Estimated Operator Reward',
flex: 1,
headerAlign: 'left',
tooltipInfo: 'Estimated reward per epoch for this profit margin if your node is selected in the active set.',
tooltipInfo:
"Estimated operator's reward (including PM and Operating Cost) in the current epoch. There are roughly 24 epochs in a day.",
},
{
field: 'selectionChance',
@@ -29,7 +31,7 @@ export const EconomicsInfoColumns: ColumnsType[] = [
flex: 1,
headerAlign: 'left',
tooltipInfo:
'Level of stake saturation for this node. Nodes receive more rewards the higher their saturation level, up to 100%. Beyond 100% no additional rewards are granted. The current stake saturation level is: 1 million NYM, computed as S/K where S is total amount of tokens available to stakeholders and K is the number of nodes in the reward set.',
'Level of stake saturation for this node. Nodes receive more rewards the higher their saturation level, up to 100%. Beyond 100% no additional rewards are granted. The current stake saturation level is: 750k NYM, computed as S/K where S is total amount of tokens available to stakeholders and K is the number of nodes in the reward set.',
},
{
field: 'profitMargin',
@@ -37,7 +39,7 @@ export const EconomicsInfoColumns: ColumnsType[] = [
flex: 1,
headerAlign: 'left',
tooltipInfo:
'Percentage of the delegates rewards that the operator takes as fee before rewards are distributed to the delegates.',
'Percentage of the delegators rewards that the operator takes as fee before rewards are distributed to the delegators.',
},
{
field: 'operatingCost',
@@ -4,23 +4,8 @@ import { ApiState, MixNodeEconomicDynamicsStatsResponse } from '../../../typeDef
import { EconomicsInfoRowWithIndex } from './types';
import { toPercentIntegerString } from '../../../utils';
const selectionChance = (economicDynamicsStats: ApiState<MixNodeEconomicDynamicsStatsResponse> | undefined) => {
const inclusionProbability = economicDynamicsStats?.data?.active_set_inclusion_probability;
// TODO: when v2 will be deployed, remove cases: VeryHigh, Moderate and VeryLow
switch (inclusionProbability) {
case 'VeryLow':
return 'Very Low';
case 'VeryHigh':
return 'Very High';
case 'High':
case 'Good':
case 'Low':
case 'Moderate':
return inclusionProbability;
default:
return '-';
}
};
const selectionChance = (economicDynamicsStats: ApiState<MixNodeEconomicDynamicsStatsResponse> | undefined) =>
economicDynamicsStats?.data?.active_set_inclusion_probability || '-';
export const EconomicsInfoRows = (): EconomicsInfoRowWithIndex => {
const { economicDynamicsStats, mixNode } = useMixnodeContext();
@@ -29,7 +14,7 @@ export const EconomicsInfoRows = (): EconomicsInfoRowWithIndex => {
currencyToString((economicDynamicsStats?.data?.estimated_total_node_reward || '').toString()) || '-';
const estimatedOperatorRewards =
currencyToString((economicDynamicsStats?.data?.estimated_operator_reward || '').toString()) || '-';
const stakeSaturation = economicDynamicsStats?.data?.stake_saturation || '-';
const stakeSaturation = economicDynamicsStats?.data?.uncapped_saturation || '-';
const profitMargin = mixNode?.data?.profit_margin_percent
? toPercentIntegerString(mixNode?.data?.profit_margin_percent)
: '-';
+3 -3
View File
@@ -31,7 +31,7 @@ export function mixNodeResponseItemToMixnodeRowType(item: MixNodeResponseItem):
const totalBond = pledge + delegations;
const selfPercentage = ((pledge * 100) / totalBond).toFixed(2);
const profitPercentage = toPercentIntegerString(item.profit_margin_percent) || 0;
const stakeSaturation = typeof item.stake_saturation === 'number' ? item.stake_saturation * 100 : 0;
const uncappedSaturation = typeof item.uncapped_saturation === 'number' ? item.uncapped_saturation * 100 : 0;
return {
mix_id: item.mix_id,
@@ -47,7 +47,7 @@ export function mixNodeResponseItemToMixnodeRowType(item: MixNodeResponseItem):
layer: item?.layer || '',
profit_percentage: `${profitPercentage}%`,
avg_uptime: `${item.avg_uptime}%` || '-',
stake_saturation: stakeSaturation,
operating_cost: `${unymToNym(item.operating_cost.amount, 6)} NYM`,
stake_saturation: uncappedSaturation,
operating_cost: `${unymToNym(item.operating_cost?.amount, 6)} NYM`,
};
}
+25 -8
View File
@@ -1,6 +1,6 @@
import * as React from 'react';
import { Link as RRDLink } from 'react-router-dom';
import { Box, Button, Card, Grid, Typography, Link as MuiLink } from '@mui/material';
import { Box, Button, Card, Grid, Link as MuiLink } from '@mui/material';
import { GridColDef, GridRenderCellParams } from '@mui/x-data-grid';
import { SelectChangeEvent } from '@mui/material/Select';
import { useMainContext } from '../../context/main';
@@ -12,6 +12,8 @@ import { Title } from '../../components/Title';
import { cellStyles, UniversalDataGrid } from '../../components/Universal-DataGrid';
import { currencyToString } from '../../utils/currency';
import { Tooltip } from '../../components/Tooltip';
import { BIG_DIPPER } from '../../api/constants';
import { splice } from '../../utils';
export const PageGateways: React.FC = () => {
const { gateways } = useMainContext();
@@ -69,9 +71,14 @@ export const PageGateways: React.FC = () => {
headerClassName: 'MuiDataGrid-header-override',
headerAlign: 'left',
renderCell: (params: GridRenderCellParams) => (
<Typography sx={cellStyles} data-testid="pledge-amount">
<MuiLink
sx={{ ...cellStyles }}
component={RRDLink}
to={`/network-components/gateway/${params.row.identityKey}`}
data-testid="pledge-amount"
>
{currencyToString(params.value)}
</Typography>
</MuiLink>
),
},
{
@@ -81,9 +88,14 @@ export const PageGateways: React.FC = () => {
headerAlign: 'left',
headerClassName: 'MuiDataGrid-header-override',
renderCell: (params: GridRenderCellParams) => (
<Typography sx={cellStyles} data-testid="host">
<MuiLink
sx={{ ...cellStyles }}
component={RRDLink}
to={`/network-components/gateway/${params.row.identityKey}`}
data-testid="host"
>
{params.value}
</Typography>
</MuiLink>
),
},
{
@@ -120,9 +132,14 @@ export const PageGateways: React.FC = () => {
headerAlign: 'left',
headerClassName: 'MuiDataGrid-header-override',
renderCell: (params: GridRenderCellParams) => (
<Typography sx={cellStyles} data-testid="owner">
{params.value}
</Typography>
<MuiLink
sx={{ ...cellStyles }}
href={`${BIG_DIPPER}/account/${params.value}`}
target="_blank"
data-testid="owner"
>
{splice(7, 29, params.value)}
</MuiLink>
),
},
];
+1 -1
View File
@@ -35,7 +35,7 @@ const columns: ColumnsType[] = [
},
{
field: 'self_percentage',
title: 'Self %',
title: 'Bond %',
headerAlign: 'left',
width: 99,
},
+4 -4
View File
@@ -149,7 +149,7 @@ export const PageMixnodes: React.FC = () => {
renderHeader: () => (
<CustomColumnHeading
headingTitle="Stake Saturation"
tooltipInfo="Level of stake saturation for this node. Nodes receive more rewards the higher their saturation level, up to 100%. Beyond 100% no additional rewards are granted. The current stake saturation level is: 1 million NYM, computed as S/K where S is total amount of tokens available to stakeholders and K is the number of nodes in the reward set."
tooltipInfo="Level of stake saturation for this node. Nodes receive more rewards the higher their saturation level, up to 100%. Beyond 100% no additional rewards are granted. The current stake saturation level is: 750k NYM, computed as S/K where S is total amount of tokens available to stakeholders and K is the number of nodes in the reward set."
/>
),
headerClassName: 'MuiDataGrid-header-override',
@@ -192,7 +192,7 @@ export const PageMixnodes: React.FC = () => {
renderHeader: () => (
<CustomColumnHeading
headingTitle="Profit Margin"
tooltipInfo="Percentage of the delegates rewards that the operator takes as fee before rewards are distributed to the delegates."
tooltipInfo="Percentage of the delegators rewards that the operator takes as fee before rewards are distributed to the delegators."
/>
),
headerClassName: 'MuiDataGrid-header-override',
@@ -210,10 +210,10 @@ export const PageMixnodes: React.FC = () => {
},
{
field: 'operating_cost',
headerName: 'Operating cost',
headerName: 'Operating Cost',
renderHeader: () => (
<CustomColumnHeading
headingTitle="Operating cost"
headingTitle="Operating Cost"
tooltipInfo="Monthly operational cost of running this node. This cost is set by the operator and it influences how the rewards are split between the operator and delegators."
/>
),
+3 -1
View File
@@ -85,6 +85,7 @@ export interface MixNodeResponseItem {
mix_node: MixNode;
avg_uptime: number;
stake_saturation: number;
uncapped_saturation: number;
operating_cost: Amount;
profit_margin_percent: string;
}
@@ -214,8 +215,9 @@ export type UptimeStoryResponse = {
export type MixNodeEconomicDynamicsStatsResponse = {
stake_saturation: number;
uncapped_saturation: number;
// TODO: when v2 will be deployed, remove cases: VeryHigh, Moderate and VeryLow
active_set_inclusion_probability: 'High' | 'Good' | 'Low' | 'VeryLow' | 'Moderate' | 'VeryHigh';
active_set_inclusion_probability: 'High' | 'Good' | 'Low';
reserve_set_inclusion_probability: 'High' | 'Good' | 'Low';
estimated_total_node_reward: number;
estimated_operator_reward: number;
@@ -179,7 +179,7 @@ const AmountFormData = ({
<CurrencyFormField
required
fullWidth
label="Operator cost"
label="Operator Cost"
autoFocus
onChanged={(newValue) => setValue('operatorCost', newValue, { shouldValidate: true })}
validationError={errors.operatorCost?.amount?.message}
@@ -152,7 +152,7 @@ export const SystemVariables = ({
<DataField
title="Node stake saturation"
info="Level of stake saturation for this node. Nodes receive more rewards the higher their saturation level, up to 100%. Beyond 100% no additional rewards are granted. The current stake saturation level is: 1 million NYM, computed as S/K where S is the total amount of tokens available to stakeholders and K is the number of nodes in the reward set."
info="Level of stake saturation for this node. Nodes receive more rewards the higher their saturation level, up to 100%. Beyond 100% no additional rewards are granted. The current stake saturation level is: 750k NYM, computed as S/K where S is the total amount of tokens available to stakeholders and K is the number of nodes in the reward set."
Indicator={<PercentIndicator value={saturation} warning={saturation >= 100} />}
/>
</Stack>