From fbf7e227acf86c3925fd22db7c5195ba524eeff1 Mon Sep 17 00:00:00 2001 From: Nathanael Liu Date: Fri, 1 Dec 2023 12:10:21 -0500 Subject: [PATCH] New fields on validator page (#214) --- .../validators/ValidatorInfoTable.tsx | 33 +++++++++++------ .../validators/ValidatorPortfolio.tsx | 12 +++---- src/hooks/useColdKey.ts | 34 ------------------ src/hooks/useValidator.ts | 10 ++++++ src/hooks/useValidatorStaked.ts | 36 ------------------- src/model/validator.ts | 2 ++ src/screens/validators.tsx | 7 ++-- src/services/validatorService.ts | 24 +++++++++++++ 8 files changed, 69 insertions(+), 89 deletions(-) delete mode 100644 src/hooks/useColdKey.ts create mode 100644 src/hooks/useValidator.ts delete mode 100644 src/hooks/useValidatorStaked.ts diff --git a/src/components/validators/ValidatorInfoTable.tsx b/src/components/validators/ValidatorInfoTable.tsx index b4965bf1..39203ae8 100644 --- a/src/components/validators/ValidatorInfoTable.tsx +++ b/src/components/validators/ValidatorInfoTable.tsx @@ -5,6 +5,9 @@ import { Currency } from "../Currency"; import { InfoTable, InfoTableAttribute } from "../InfoTable"; import { rawAmountToDecimal } from "../../utils/number"; import { useAppStats } from "../../contexts"; +import { Resource } from "../../model/resource"; +import { Validator } from "../../model/validator"; +import { AccountAddress } from "../AccountAddress"; const addressItem = css` overflow: hidden; @@ -15,33 +18,35 @@ const addressItem = css` export type ValidatorInfoTableProps = { account: string; balance: any; + info: Resource; }; const ValidatorInfoTableAttribute = InfoTableAttribute; export const ValidatorInfoTable = (props: ValidatorInfoTableProps) => { - const { account, balance } = props; + const { account, balance, info } = props; - const { currency } = NETWORK_CONFIG; + const { currency, prefix } = NETWORK_CONFIG; const { state: { tokenLoading, tokenStats }, } = useAppStats(); const dominance = - tokenLoading || tokenStats === undefined || tokenStats.delegatedSupply === 0 - ? 0 - : ( - (rawAmountToDecimal(balance.data).toNumber() / - tokenStats.delegatedSupply) * 100 - ).toFixed(2); + tokenLoading || tokenStats === undefined || tokenStats.delegatedSupply === 0 + ? 0 + : ( + (rawAmountToDecimal(balance.data).toNumber() / + tokenStats.delegatedSupply) * + 100 + ).toFixed(2); return ( { label="Dominance" render={() =>
{dominance}%
} /> + ( + + )} + />
); }; diff --git a/src/components/validators/ValidatorPortfolio.tsx b/src/components/validators/ValidatorPortfolio.tsx index a794c9ca..ad4eda81 100644 --- a/src/components/validators/ValidatorPortfolio.tsx +++ b/src/components/validators/ValidatorPortfolio.tsx @@ -1,14 +1,14 @@ /** @jsxImportSource @emotion/react */ import { css } from "@emotion/react"; import { formatNumber, rawAmountToDecimal } from "../../utils/number"; -import { useColdKey } from "../../hooks/useColdKey"; -import { useValidatorStaked } from "../../hooks/useValidatorStaked"; import { useValidatorBalance } from "../../hooks/useValidatorBalance"; import { StatItem } from "../network/StatItem"; import { DonutChart } from "../DonutChart"; import Loading from "../Loading"; import { useState, useEffect } from "react"; import { countNominators } from "../../services/delegateService"; +import { Resource } from "../../model/resource"; +import { Validator } from "../../model/validator"; const chartContainer = css` display: flex; @@ -34,15 +34,15 @@ const spinnerContainer = css` export type ValidatorPortfolioProps = { hotkey: string; + info: Resource; }; export const ValidatorPortfolio = (props: ValidatorPortfolioProps) => { - const { hotkey } = props; + const { hotkey, info } = props; const balance = useValidatorBalance({ address: { equalTo: hotkey } }); - const coldKey = useColdKey(hotkey); - const validatorStaked = useValidatorStaked(hotkey, coldKey); - const loading = balance.loading || validatorStaked === undefined; + const loading = balance.loading || info.loading; + const validatorStaked = info.data?.validatorStake.toString(); const validatorStakedFormatted = loading ? 0 : formatNumber(rawAmountToDecimal(validatorStaked), { decimalPlaces: 2 }); diff --git a/src/hooks/useColdKey.ts b/src/hooks/useColdKey.ts deleted file mode 100644 index 98ed79d2..00000000 --- a/src/hooks/useColdKey.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { useEffect, useState } from "react"; -import { useApi } from "../contexts"; - -export function useColdKey(hotkey: string) { - const { - state: { api, apiState }, - } = useApi(); - const [coldKey, setColdKey] = useState(undefined); - const [unsub, setUnsub] = useState(undefined); - - const subscribeColdKey = async () => { - if (!api || apiState !== "READY") return; - const _unsub = await api.query.subtensorModule?.owner( - hotkey, - (value: any) => { - if (!value || value.isEmpty) { - console.log("Failed to get cold key"); - return; - } - value && setColdKey(value.toHuman()); - } - ); - setUnsub(_unsub); - }; - - useEffect(() => { - subscribeColdKey(); - return () => { - if (unsub) unsub.then(); - }; - }, [hotkey, apiState]); - - return coldKey; -} diff --git a/src/hooks/useValidator.ts b/src/hooks/useValidator.ts new file mode 100644 index 00000000..e3a1923c --- /dev/null +++ b/src/hooks/useValidator.ts @@ -0,0 +1,10 @@ +import { FetchOptions } from "../model/fetchOptions"; +import { ValidatorsFilter, getValidator } from "../services/validatorService"; + +import { useResource } from "./useResource"; + +export function useValidator( + filter: ValidatorsFilter, + options?: FetchOptions) { + return useResource(getValidator, [filter], options); +} diff --git a/src/hooks/useValidatorStaked.ts b/src/hooks/useValidatorStaked.ts deleted file mode 100644 index e87fd98f..00000000 --- a/src/hooks/useValidatorStaked.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { useEffect, useState } from "react"; -import { useApi } from "../contexts"; - -export function useValidatorStaked(hotkey: any, coldkey: any) { - const { - state: { api, apiState }, - } = useApi(); - const [staked, setStaked] = useState(undefined); - const [unsub, setUnsub] = useState(undefined); - - const subscribeValidatorStaked = async () => { - if (!api || apiState !== "READY") return; - const _unsub = await api.query.subtensorModule?.stake( - hotkey, - coldkey, - (value: any) => { - if (!value || value.isEmpty) { - console.log("Failed to get cold key"); - return; - } - value && setStaked(value.toString()); - } - ); - setUnsub(_unsub); - }; - - useEffect(() => { - if(!coldkey) return; - subscribeValidatorStaked(); - return () => { - if (unsub) unsub.then(); - }; - }, [hotkey, coldkey, apiState]); - - return staked; -} diff --git a/src/model/validator.ts b/src/model/validator.ts index a97e58b4..c9e24c54 100644 --- a/src/model/validator.ts +++ b/src/model/validator.ts @@ -10,6 +10,8 @@ export type Validator = { rank: bigint; amountChange: bigint; nominatorChange: bigint; + owner: string; + validatorStake: bigint; name?: string; }; diff --git a/src/screens/validators.tsx b/src/screens/validators.tsx index 70badcbc..3064cf85 100644 --- a/src/screens/validators.tsx +++ b/src/screens/validators.tsx @@ -24,6 +24,7 @@ import { ValidatorPortfolio } from "../components/validators/ValidatorPortfolio" import { ValidatorStakeHistoryChart } from "../components/validators/ValidatorStakeHistoryChart"; import { useValidatorStakeHistory } from "../hooks/useValidatorHistory"; import { useVerifiedDelegates } from "../hooks/useVerifiedDelegates"; +import { useValidator } from "../hooks/useValidator"; const validatorHeader = (theme: Theme) => css` display: flex; @@ -100,6 +101,8 @@ export type ValidatorPageParams = { export const ValidatorPage = () => { const { address } = useParams() as ValidatorPageParams; + const validator = useValidator({ address: { equalTo: address } }); + const verifiedDelegates = useVerifiedDelegates(); const info = verifiedDelegates[address]; @@ -192,7 +195,7 @@ export const ValidatorPage = () => { {info?.description && (
{info?.description}
)} - +
{
- + diff --git a/src/services/validatorService.ts b/src/services/validatorService.ts index 08ba29fc..8c1eb9c1 100644 --- a/src/services/validatorService.ts +++ b/src/services/validatorService.ts @@ -22,6 +22,26 @@ export type ValidatorsOrder = | "NOMINATORS_ASC" | "NOMINATORS_DESC"; +export async function getValidator(filter: ValidatorsFilter) { + const response = await fetchIndexer<{ validators: ResponseItems }>( + `query ($filter: ValidatorFilter) { + validators(first: 1, offset: 0, filter: $filter, orderBy: ID_DESC) { + nodes { + id + owner + validatorStake + } + } + }`, + { + filter, + } + ); + + const data = response.validators?.nodes[0] && transformValidator(response.validators.nodes[0]); + return data; +} + export async function getValidators( order: ValidatorsOrder = "AMOUNT_DESC", pagination: PaginationOptions @@ -113,3 +133,7 @@ export async function getValidatorStakeHistory( data: response.validators?.nodes, }; } + +const transformValidator = (validator: Validator): Validator => { + return validator; +};