From 7ff2b0e23e1ff2eda4acf8c3c8141094e0e9a061 Mon Sep 17 00:00:00 2001 From: Michal Zielenkiewicz Date: Mon, 15 Dec 2025 12:38:32 +0100 Subject: [PATCH 1/3] Update API bindings --- src/oasis-nexus/generated/api.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/oasis-nexus/generated/api.ts b/src/oasis-nexus/generated/api.ts index 81aab94686..41a36d067f 100644 --- a/src/oasis-nexus/generated/api.ts +++ b/src/oasis-nexus/generated/api.ts @@ -643,7 +643,7 @@ export type ValidatorList = List & ValidatorListAllOf; export interface ValidatorAggStats { /** The total voting power across all validators. */ - total_voting_power: number; + total_voting_power: TextBigInt; /** The total number of delegators in the network. */ total_delegators: number; /** The total amount of token staked to validators. */ @@ -686,9 +686,9 @@ export interface Validator { /** The escrow account data for this validator. */ escrow: Escrow; /** The voting power of this validator. */ - voting_power: number; + voting_power: TextBigInt; /** The cumulative voting power of this validator and all other validators ranked higher than itself. */ - voting_power_cumulative?: number; + voting_power_cumulative?: TextBigInt; /** Whether the entity has a node that is registered for being a validator, node is up to date, and has successfully registered itself. It may or may not be part of validator set. */ active: boolean; /** The second-granular consensus time. */ From 14882566ae573a8d9de4a30fd1f018c309589785 Mon Sep 17 00:00:00 2001 From: Michal Zielenkiewicz Date: Mon, 15 Dec 2025 12:40:21 +0100 Subject: [PATCH 2/3] Align components with API changes and keep backward compatibility --- .changelog/2399.bugfix.md | 1 + src/app/components/LabeledProgress/index.tsx | 16 +++++++++++++--- src/app/components/PercentageValue/index.tsx | 16 ++++++++++++---- .../Validators/ValidatorCumulativeVoting.tsx | 16 ++++++++++++---- .../ValidatorDetailsPage/VotingPowerCard.tsx | 7 ++++--- src/app/pages/ValidatorDetailsPage/index.tsx | 7 ++++--- 6 files changed, 46 insertions(+), 17 deletions(-) create mode 100644 .changelog/2399.bugfix.md diff --git a/.changelog/2399.bugfix.md b/.changelog/2399.bugfix.md new file mode 100644 index 0000000000..d5d155d246 --- /dev/null +++ b/.changelog/2399.bugfix.md @@ -0,0 +1 @@ +Prepare Explorer for incoming breaking changes in Nexus API diff --git a/src/app/components/LabeledProgress/index.tsx b/src/app/components/LabeledProgress/index.tsx index 9536cef1e5..df1e64a354 100644 --- a/src/app/components/LabeledProgress/index.tsx +++ b/src/app/components/LabeledProgress/index.tsx @@ -1,9 +1,10 @@ import { FC, ReactNode } from 'react' import { Progress } from '@oasisprotocol/ui-library/src/components/progress' +import BigNumber from 'bignumber.js' type LabeledProgresssProps = { - value?: number - max?: number + value?: number | string + max?: number | string label: ReactNode } @@ -12,9 +13,18 @@ export const LabeledProgress: FC = ({ value, max, label } return null } + const progressValue = new BigNumber(value) + const progressMax = new BigNumber(max) + + if (!progressValue || !progressMax || progressMax.lte(0)) { + return null + } + + const percentage = progressValue.div(progressMax).multipliedBy(100).toNumber() + return (
- + {label} diff --git a/src/app/components/PercentageValue/index.tsx b/src/app/components/PercentageValue/index.tsx index 3d87497059..4a1a0152d7 100644 --- a/src/app/components/PercentageValue/index.tsx +++ b/src/app/components/PercentageValue/index.tsx @@ -1,10 +1,11 @@ import { FC } from 'react' import { useTranslation } from 'react-i18next' +import BigNumber from 'bignumber.js' type PercentageValueProps = { adaptMaximumFractionDigits?: boolean - total?: number - value: number | undefined + total?: number | string + value: number | string | undefined maximumFractionDigits?: number } @@ -16,11 +17,18 @@ export const PercentageValue: FC = ({ }) => { const { t } = useTranslation() - if (typeof value !== 'number' || typeof total !== 'number' || total <= 0) { + if (value === undefined || value === null || total === undefined || total === null) { return null } - const percentageValue = value / total + const votes = new BigNumber(value) + const totalVotes = new BigNumber(total) + + if (!votes || !totalVotes || totalVotes.lte(0)) { + return null + } + + const percentageValue = votes.div(totalVotes).toNumber() return ( <> diff --git a/src/app/components/Validators/ValidatorCumulativeVoting.tsx b/src/app/components/Validators/ValidatorCumulativeVoting.tsx index 888f3e1a44..0dff45c25a 100644 --- a/src/app/components/Validators/ValidatorCumulativeVoting.tsx +++ b/src/app/components/Validators/ValidatorCumulativeVoting.tsx @@ -1,10 +1,11 @@ import { FC } from 'react' import { PercentageValue } from '../PercentageValue' +import BigNumber from 'bignumber.js' type ValidatorCumulativeVotingProps = { containerMarginThemeSpacing: number - value: number | undefined - total: number | undefined + value: number | string | undefined + total: number | string | undefined } export const ValidatorCumulativeVoting: FC = ({ @@ -12,11 +13,18 @@ export const ValidatorCumulativeVoting: FC = ({ value, total, }) => { - if (typeof value !== 'number' || typeof total !== 'number' || total <= 0) { + if (value === undefined || value === null || total === undefined || total === null) { return null } - const percentage = (value / total) * 100 + const votes = new BigNumber(value) + const totalVotes = new BigNumber(total) + + if (!votes || !totalVotes || totalVotes.lte(0)) { + return null + } + + const percentage = votes.div(totalVotes).multipliedBy(100).toNumber() return (
diff --git a/src/app/pages/ValidatorDetailsPage/VotingPowerCard.tsx b/src/app/pages/ValidatorDetailsPage/VotingPowerCard.tsx index d1477711e8..e8ee811415 100644 --- a/src/app/pages/ValidatorDetailsPage/VotingPowerCard.tsx +++ b/src/app/pages/ValidatorDetailsPage/VotingPowerCard.tsx @@ -1,6 +1,7 @@ import { FC } from 'react' import { useTranslation } from 'react-i18next' import { Typography } from '@oasisprotocol/ui-library/src/components/typography' +import BigNumber from 'bignumber.js' import { Validator, ValidatorAggStats } from '../../../oasis-nexus/api' import { SnapshotTextCard } from '../../components/Snapshots/SnapshotCard' import { LabeledProgress } from 'app/components/LabeledProgress' @@ -18,13 +19,13 @@ export const VotingPowerCard: FC = ({ validator, stats }) ({validator?.voting_power.toLocaleString()}) + validator?.voting_power !== undefined && ( + ({new BigNumber(validator?.voting_power).toFormat()}) ) } withContentPadding={false} > - {typeof validator?.voting_power === 'number' && stats?.total_voting_power && ( + {validator?.voting_power !== undefined && stats?.total_voting_power && ( <> {t('validator.votingPowerOverall')} diff --git a/src/app/pages/ValidatorDetailsPage/index.tsx b/src/app/pages/ValidatorDetailsPage/index.tsx index 852fe64c37..2cbcb1960e 100644 --- a/src/app/pages/ValidatorDetailsPage/index.tsx +++ b/src/app/pages/ValidatorDetailsPage/index.tsx @@ -2,6 +2,7 @@ import { FC } from 'react' import { useTranslation } from 'react-i18next' import { useHref, useLoaderData } from 'react-router-dom' import { Card, CardContent } from '@oasisprotocol/ui-library/src/components/cards' +import BigNumber from 'bignumber.js' import { Validator, ValidatorAggStats, @@ -229,17 +230,17 @@ export const ValidatorDetailsView: FC<{
{formattedTime}
)} - {typeof validator.voting_power === 'number' && ( + {validator.voting_power !== undefined && ( <>
{t('validator.votingPower')}
{stats?.total_voting_power ? ( <> -   ({validator.voting_power.toLocaleString()}) +   ({new BigNumber(validator.voting_power).toFormat()}) ) : ( - validator.voting_power.toLocaleString() + new BigNumber(validator.voting_power).toFormat() )}
From ff4576928b77fb59075aaf966482538b1b987b65 Mon Sep 17 00:00:00 2001 From: Michal Zielenkiewicz Date: Thu, 18 Dec 2025 09:31:41 +0100 Subject: [PATCH 3/3] Move percentage logic to number utils --- src/app/components/LabeledProgress/index.tsx | 13 +++--------- src/app/components/PercentageValue/index.tsx | 13 +++--------- .../Validators/ValidatorCumulativeVoting.tsx | 13 +++--------- src/app/utils/number-utils.ts | 20 +++++++++++++++++++ 4 files changed, 29 insertions(+), 30 deletions(-) diff --git a/src/app/components/LabeledProgress/index.tsx b/src/app/components/LabeledProgress/index.tsx index df1e64a354..3fea963990 100644 --- a/src/app/components/LabeledProgress/index.tsx +++ b/src/app/components/LabeledProgress/index.tsx @@ -1,6 +1,6 @@ import { FC, ReactNode } from 'react' import { Progress } from '@oasisprotocol/ui-library/src/components/progress' -import BigNumber from 'bignumber.js' +import { calculatePercentage } from '../../utils/number-utils' type LabeledProgresssProps = { value?: number | string @@ -9,19 +9,12 @@ type LabeledProgresssProps = { } export const LabeledProgress: FC = ({ value, max, label }) => { - if (!value || !max) { - return null - } + const percentage = calculatePercentage(value, max) - const progressValue = new BigNumber(value) - const progressMax = new BigNumber(max) - - if (!progressValue || !progressMax || progressMax.lte(0)) { + if (percentage === null) { return null } - const percentage = progressValue.div(progressMax).multipliedBy(100).toNumber() - return (
diff --git a/src/app/components/PercentageValue/index.tsx b/src/app/components/PercentageValue/index.tsx index 4a1a0152d7..312def4edc 100644 --- a/src/app/components/PercentageValue/index.tsx +++ b/src/app/components/PercentageValue/index.tsx @@ -1,6 +1,6 @@ import { FC } from 'react' import { useTranslation } from 'react-i18next' -import BigNumber from 'bignumber.js' +import { calculatePercentage } from '../../utils/number-utils' type PercentageValueProps = { adaptMaximumFractionDigits?: boolean @@ -17,19 +17,12 @@ export const PercentageValue: FC = ({ }) => { const { t } = useTranslation() - if (value === undefined || value === null || total === undefined || total === null) { - return null - } + const percentageValue = calculatePercentage(value, total, false) - const votes = new BigNumber(value) - const totalVotes = new BigNumber(total) - - if (!votes || !totalVotes || totalVotes.lte(0)) { + if (percentageValue === null) { return null } - const percentageValue = votes.div(totalVotes).toNumber() - return ( <> {t('common.valuePair', { diff --git a/src/app/components/Validators/ValidatorCumulativeVoting.tsx b/src/app/components/Validators/ValidatorCumulativeVoting.tsx index 0dff45c25a..654a1b9f4b 100644 --- a/src/app/components/Validators/ValidatorCumulativeVoting.tsx +++ b/src/app/components/Validators/ValidatorCumulativeVoting.tsx @@ -1,6 +1,6 @@ import { FC } from 'react' import { PercentageValue } from '../PercentageValue' -import BigNumber from 'bignumber.js' +import { calculatePercentage } from '../../utils/number-utils' type ValidatorCumulativeVotingProps = { containerMarginThemeSpacing: number @@ -13,19 +13,12 @@ export const ValidatorCumulativeVoting: FC = ({ value, total, }) => { - if (value === undefined || value === null || total === undefined || total === null) { - return null - } + const percentage = calculatePercentage(value, total) - const votes = new BigNumber(value) - const totalVotes = new BigNumber(total) - - if (!votes || !totalVotes || totalVotes.lte(0)) { + if (percentage === null) { return null } - const percentage = votes.div(totalVotes).multipliedBy(100).toNumber() - return (
{ } export const convertToNano = (value: string): string => fromBaseUnits(value, -9) + +export const calculatePercentage = ( + value: number | string | undefined, + total: number | string | undefined, + asPercentage: boolean = true, +): number | null => { + if (value === undefined || value === null || total === undefined || total === null) { + return null + } + + const valueBN = new BigNumber(value) + const totalBN = new BigNumber(total) + + if (!valueBN || !totalBN || totalBN.lte(0)) { + return null + } + + const result = valueBN.div(totalBN) + return asPercentage ? result.multipliedBy(100).toNumber() : result.toNumber() +}