diff --git a/src/features/staking/components/main-page.tsx b/src/features/staking/components/main-page.tsx index 22cbb61..050bd67 100644 --- a/src/features/staking/components/main-page.tsx +++ b/src/features/staking/components/main-page.tsx @@ -3,10 +3,9 @@ import { useAbstraxionSigningClient, useModal } from "@burnt-labs/abstraxion"; import { Button } from "@burnt-labs/ui"; import type { Coin } from "@cosmjs/stargate"; -import type { NewBlockEvent } from "@cosmjs/tendermint-rpc/build/tendermint34/responses"; import type { Validator } from "cosmjs-types/cosmos/staking/v1beta1/staking"; import Link from "next/link"; -import { memo, useEffect, useMemo, useState } from "react"; +import { memo, useMemo, useState } from "react"; import { toast } from "react-toastify"; import { @@ -16,11 +15,14 @@ import { } from "../context/actions"; import { useStaking } from "../context/hooks"; import { getTotalDelegation, getTotalUnbonding } from "../context/selectors"; -import { getAccountExplorerLink } from "../lib/core/accounts"; -import { subscribeToLastBlock } from "../lib/core/base"; +import { useSubscribeLastBlockHeader } from "../hooks"; import { sumAllCoins } from "../lib/core/coins"; +import { + getAccountExplorerLink, + getBlockExplorerLink, +} from "../lib/core/explorer"; import type { StakeAddresses } from "../lib/core/tx"; -import { formatCoin } from "../lib/formatters"; +import { formatCoin, formatLastBlockTime } from "../lib/formatters"; import DebugAccount from "./debug-account"; import ValidatorRow from "./validator-row"; @@ -33,32 +35,7 @@ function StakingPage() { const { client } = useAbstraxionSigningClient(); const [, setShowAbstraxion] = useModal(); - const [lastBlock, setLastBlock] = useState(null); - - useEffect(() => { - let unsubscribe = () => {}; - - subscribeToLastBlock( - (newLastBlock) => { - setLastBlock(newLastBlock); - }, - (err: unknown) => { - // eslint-disable-next-line no-console - console.log("debug: main-page.tsx: err", err); - }, - () => { - // eslint-disable-next-line no-console - console.log("Subscription Completed"); - setLastBlock(null); - }, - ).then((fn) => { - unsubscribe = fn; - }); - - return () => { - unsubscribe?.(); - }; - }, []); + const lastBlockHeader = useSubscribeLastBlockHeader(); const validatorsMap: Record = useMemo( () => @@ -96,7 +73,23 @@ function StakingPage() { Open Settings - {!!lastBlock &&
Block: #{lastBlock.header.height}
} + {!!lastBlockHeader && ( + <> +
+ Last block time: {formatLastBlockTime(lastBlockHeader.time)} +
+
+ Block:{" "} + + #{lastBlockHeader.height} + +
+ + )} {tokens && (
Tokens: {formatCoin(tokens)} diff --git a/src/features/staking/components/validator-page.tsx b/src/features/staking/components/validator-page.tsx index 6b566a3..808fee7 100644 --- a/src/features/staking/components/validator-page.tsx +++ b/src/features/staking/components/validator-page.tsx @@ -9,7 +9,7 @@ import { useEffect, useState } from "react"; import { getValidatorDetailsAction } from "../context/actions"; import { useStaking } from "../context/hooks"; import { getVotingPowerPerc } from "../context/selectors"; -import { getValidatorExplorerLink } from "../lib/core/accounts"; +import { getValidatorExplorerLink } from "../lib/core/explorer"; import { formatCommission, formatVotingPowerPerc } from "../lib/formatters"; import { keybaseClient } from "../lib/utils/keybase-client"; diff --git a/src/features/staking/hooks.ts b/src/features/staking/hooks.ts new file mode 100644 index 0000000..ff61f07 --- /dev/null +++ b/src/features/staking/hooks.ts @@ -0,0 +1,42 @@ +import type { NewBlockHeaderEvent } from "@cosmjs/tendermint-rpc/build/tendermint34/responses"; +import { useEffect, useState } from "react"; + +import { subscribeToLastBlockHeader } from "./lib/core/base"; + +export const useSubscribeLastBlockHeader = () => { + const [lastBlockHeader, setLastBlockHeader] = + useState(null); + + useEffect(() => { + let unsubscribe = () => {}; + let unmounted = false; + + subscribeToLastBlockHeader( + (newLastBlockHeader) => { + setLastBlockHeader(newLastBlockHeader); + }, + (err: unknown) => { + // eslint-disable-next-line no-console + console.log("debug: hooks.ts: err", err); + }, + () => { + // eslint-disable-next-line no-console + console.log("Subscription Completed"); + setLastBlockHeader(null); + }, + ).then((fn) => { + if (unmounted) { + fn(); + } else { + unsubscribe = fn; + } + }); + + return () => { + unsubscribe(); + unmounted = true; + }; + }, []); + + return lastBlockHeader; +}; diff --git a/src/features/staking/lib/core/base.ts b/src/features/staking/lib/core/base.ts index b6ff1ed..f24f7c5 100644 --- a/src/features/staking/lib/core/base.ts +++ b/src/features/staking/lib/core/base.ts @@ -1,5 +1,5 @@ import { StargateClient } from "@cosmjs/stargate"; -import type { NewBlockEvent } from "@cosmjs/tendermint-rpc/build/tendermint34/responses"; +import type { NewBlockHeaderEvent } from "@cosmjs/tendermint-rpc/build/tendermint34/responses"; import BigNumber from "bignumber.js"; import type { QueryValidatorsResponse } from "cosmjs-types/cosmos/staking/v1beta1/query"; import type { @@ -121,19 +121,19 @@ export const getRewards = async (address: string, validatorAddress: string) => { .map((r) => normaliseCoin(r)); }; -export const subscribeToLastBlock = async ( - onNext: (b: NewBlockEvent) => void, - onError: (err: unknown) => void, - onComplete: () => void, +export const subscribeToLastBlockHeader = async ( + next: (b: NewBlockHeaderEvent) => void, + error: (err: unknown) => void, + complete: () => void, ) => { const wsClient = await getWSClient(); - const subscription = wsClient.subscribeNewBlock(); + const subscription = wsClient.subscribeNewBlockHeader(); const listener = { - complete: onComplete, - error: onError, - next: onNext, + complete, + error, + next, }; subscription.addListener(listener); diff --git a/src/features/staking/lib/core/accounts.ts b/src/features/staking/lib/core/explorer.ts similarity index 70% rename from src/features/staking/lib/core/accounts.ts rename to src/features/staking/lib/core/explorer.ts index 665b266..a441b34 100644 --- a/src/features/staking/lib/core/accounts.ts +++ b/src/features/staking/lib/core/explorer.ts @@ -5,3 +5,6 @@ export const getAccountExplorerLink = (address: string) => export const getValidatorExplorerLink = (address: string) => `https://explorer.burnt.com/${chainId}/staking/${address}`; + +export const getBlockExplorerLink = (blockNum: number) => + `https://explorer.burnt.com/${chainId}/block/${blockNum}`; diff --git a/src/features/staking/lib/formatters.ts b/src/features/staking/lib/formatters.ts index fedc0c5..84c64e2 100644 --- a/src/features/staking/lib/formatters.ts +++ b/src/features/staking/lib/formatters.ts @@ -1,4 +1,5 @@ import type { Coin } from "@cosmjs/stargate"; +import type { ReadonlyDateWithNanoseconds } from "@cosmjs/tendermint-rpc/build/dates"; import BigNumber from "bignumber.js"; import { normaliseCoin } from "./core/coins"; @@ -27,3 +28,10 @@ export const formatCommission = (commissionRate: string) => { return `${(comission * 100).toFixed(0)}%`; }; + +export const formatLastBlockTime = (time: ReadonlyDateWithNanoseconds) => + [ + time.getHours().toString().padStart(2, "0"), + time.getMinutes().toString().padStart(2, "0"), + time.getSeconds().toString().padStart(2, "0"), + ].join(":");