From baa61c07d5dd7e0485d8fae5ea95fe353fb14874 Mon Sep 17 00:00:00 2001 From: Fouad Date: Wed, 9 Nov 2022 12:39:14 +0000 Subject: [PATCH] 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 --- explorer-api/src/mix_node/econ_stats.rs | 2 ++ explorer-api/src/mix_node/models.rs | 2 ++ explorer-api/src/mix_nodes/models.rs | 2 ++ .../components/MixNodes/Economics/Columns.ts | 10 +++--- .../src/components/MixNodes/Economics/Rows.ts | 21 ++---------- explorer/src/components/MixNodes/index.ts | 6 ++-- explorer/src/pages/Gateways/index.tsx | 33 ++++++++++++++----- explorer/src/pages/MixnodeDetail/index.tsx | 2 +- explorer/src/pages/Mixnodes/index.tsx | 8 ++--- explorer/src/typeDefs/explorer-api.ts | 4 ++- .../Bonding/forms/BondGatewayForm.tsx | 2 +- .../src/pages/settings/system-variables.tsx | 2 +- 12 files changed, 53 insertions(+), 41 deletions(-) diff --git a/explorer-api/src/mix_node/econ_stats.rs b/explorer-api/src/mix_node/econ_stats.rs index 22f106b1aa..cde29d3a86 100644 --- a/explorer-api/src/mix_node/econ_stats.rs +++ b/explorer-api/src/mix_node/econ_stats.rs @@ -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 diff --git a/explorer-api/src/mix_node/models.rs b/explorer-api/src/mix_node/models.rs index 1d709433b1..ef894e4b40 100644 --- a/explorer-api/src/mix_node/models.rs +++ b/explorer-api/src/mix_node/models.rs @@ -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, diff --git a/explorer-api/src/mix_nodes/models.rs b/explorer-api/src/mix_nodes/models.rs index 07899742c9..8dc9c96ac3 100644 --- a/explorer-api/src/mix_nodes/models.rs +++ b/explorer-api/src/mix_nodes/models.rs @@ -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(), diff --git a/explorer/src/components/MixNodes/Economics/Columns.ts b/explorer/src/components/MixNodes/Economics/Columns.ts index 40fef70b68..133551bcc6 100644 --- a/explorer/src/components/MixNodes/Economics/Columns.ts +++ b/explorer/src/components/MixNodes/Economics/Columns.ts @@ -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', diff --git a/explorer/src/components/MixNodes/Economics/Rows.ts b/explorer/src/components/MixNodes/Economics/Rows.ts index a4f998a1f0..61049a5ca3 100644 --- a/explorer/src/components/MixNodes/Economics/Rows.ts +++ b/explorer/src/components/MixNodes/Economics/Rows.ts @@ -4,23 +4,8 @@ import { ApiState, MixNodeEconomicDynamicsStatsResponse } from '../../../typeDef import { EconomicsInfoRowWithIndex } from './types'; import { toPercentIntegerString } from '../../../utils'; -const selectionChance = (economicDynamicsStats: ApiState | 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 | 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) : '-'; diff --git a/explorer/src/components/MixNodes/index.ts b/explorer/src/components/MixNodes/index.ts index 3435c3bf3f..6c41fb206d 100644 --- a/explorer/src/components/MixNodes/index.ts +++ b/explorer/src/components/MixNodes/index.ts @@ -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`, }; } diff --git a/explorer/src/pages/Gateways/index.tsx b/explorer/src/pages/Gateways/index.tsx index 6b557d593f..2430e4f9a5 100644 --- a/explorer/src/pages/Gateways/index.tsx +++ b/explorer/src/pages/Gateways/index.tsx @@ -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) => ( - + {currencyToString(params.value)} - + ), }, { @@ -81,9 +88,14 @@ export const PageGateways: React.FC = () => { headerAlign: 'left', headerClassName: 'MuiDataGrid-header-override', renderCell: (params: GridRenderCellParams) => ( - + {params.value} - + ), }, { @@ -120,9 +132,14 @@ export const PageGateways: React.FC = () => { headerAlign: 'left', headerClassName: 'MuiDataGrid-header-override', renderCell: (params: GridRenderCellParams) => ( - - {params.value} - + + {splice(7, 29, params.value)} + ), }, ]; diff --git a/explorer/src/pages/MixnodeDetail/index.tsx b/explorer/src/pages/MixnodeDetail/index.tsx index ac53ebebf0..266c13be3a 100644 --- a/explorer/src/pages/MixnodeDetail/index.tsx +++ b/explorer/src/pages/MixnodeDetail/index.tsx @@ -35,7 +35,7 @@ const columns: ColumnsType[] = [ }, { field: 'self_percentage', - title: 'Self %', + title: 'Bond %', headerAlign: 'left', width: 99, }, diff --git a/explorer/src/pages/Mixnodes/index.tsx b/explorer/src/pages/Mixnodes/index.tsx index f37707c134..c502799c54 100644 --- a/explorer/src/pages/Mixnodes/index.tsx +++ b/explorer/src/pages/Mixnodes/index.tsx @@ -149,7 +149,7 @@ export const PageMixnodes: React.FC = () => { renderHeader: () => ( ), headerClassName: 'MuiDataGrid-header-override', @@ -192,7 +192,7 @@ export const PageMixnodes: React.FC = () => { renderHeader: () => ( ), headerClassName: 'MuiDataGrid-header-override', @@ -210,10 +210,10 @@ export const PageMixnodes: React.FC = () => { }, { field: 'operating_cost', - headerName: 'Operating cost', + headerName: 'Operating Cost', renderHeader: () => ( ), diff --git a/explorer/src/typeDefs/explorer-api.ts b/explorer/src/typeDefs/explorer-api.ts index a01b87a1a9..f8350775c4 100644 --- a/explorer/src/typeDefs/explorer-api.ts +++ b/explorer/src/typeDefs/explorer-api.ts @@ -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; diff --git a/nym-wallet/src/components/Bonding/forms/BondGatewayForm.tsx b/nym-wallet/src/components/Bonding/forms/BondGatewayForm.tsx index bf0511d51a..4ac0e47aaf 100644 --- a/nym-wallet/src/components/Bonding/forms/BondGatewayForm.tsx +++ b/nym-wallet/src/components/Bonding/forms/BondGatewayForm.tsx @@ -179,7 +179,7 @@ const AmountFormData = ({ setValue('operatorCost', newValue, { shouldValidate: true })} validationError={errors.operatorCost?.amount?.message} diff --git a/nym-wallet/src/pages/settings/system-variables.tsx b/nym-wallet/src/pages/settings/system-variables.tsx index 015034f76e..761d98444c 100644 --- a/nym-wallet/src/pages/settings/system-variables.tsx +++ b/nym-wallet/src/pages/settings/system-variables.tsx @@ -152,7 +152,7 @@ export const SystemVariables = ({ = 100} />} />