From d540c64bad98c3e7f742f55e4b9fe5ca72e5e3da Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 13 Jan 2025 12:18:31 +0100 Subject: [PATCH] Load unbonded and unbonding validators too --- components/SelectValidator.tsx | 5 +- components/forms/OldCreateTxForm/index.tsx | 3 +- context/ChainsContext/index.tsx | 12 ++--- context/ChainsContext/types.tsx | 4 +- lib/staking.ts | 58 +++++++++++++++++++--- 5 files changed, 65 insertions(+), 17 deletions(-) diff --git a/components/SelectValidator.tsx b/components/SelectValidator.tsx index d07ec6a..0b3376a 100644 --- a/components/SelectValidator.tsx +++ b/components/SelectValidator.tsx @@ -25,11 +25,13 @@ export default function SelectValidator({ setValidatorAddress, }: SelectValidatorProps) { const { - validatorState: { validators }, + validatorState: { validators: { bonded, unbonding, unbonded} }, } = useChains(); const [open, setOpen] = useState(false); const [searchText, setSearchText] = useState(""); + const validators = [...bonded, ...unbonding, ...unbonded]; + return ( @@ -73,6 +75,7 @@ export default function SelectValidator({ : "opacity-0", )} /> + {validatorItem.jailed ? <>jailed{" "} : null} {validatorItem.description.moniker} ))} diff --git a/components/forms/OldCreateTxForm/index.tsx b/components/forms/OldCreateTxForm/index.tsx index a0e9f15..7e6988e 100644 --- a/components/forms/OldCreateTxForm/index.tsx +++ b/components/forms/OldCreateTxForm/index.tsx @@ -52,7 +52,8 @@ const OldCreateTxForm = ({ router, senderAddress, accountOnChain }: OldCreateTxF }; const addMsgWithValidator = (newMsgType: MsgTypeUrl) => { - if (!validators.length) { + const validatorsLoaded = !!validators.bonded.length; + if (!validatorsLoaded) { loadValidators(chainsDispatch); } diff --git a/context/ChainsContext/index.tsx b/context/ChainsContext/index.tsx index 03974df..ad8078c 100644 --- a/context/ChainsContext/index.tsx +++ b/context/ChainsContext/index.tsx @@ -1,10 +1,10 @@ -import { getAllValidators } from "@/lib/staking"; +import { emptyAllValidatorsEmpty, getAllValidators } from "@/lib/staking"; import { toastError } from "@/lib/utils"; import { ReactNode, createContext, useContext, useEffect, useReducer } from "react"; import { emptyChain, isChainInfoFilled, setChain, setChains, setChainsError } from "./helpers"; import { getChain, getNodeFromArray, useChainsFromRegistry } from "./service"; import { addLocalChainInStorage, addRecentChainNameInStorage, setChainInUrl } from "./storage"; -import { Action, ChainsContextType, State } from "./types"; +import { Action, ChainsContextType, Dispatch, State } from "./types"; const ChainsContext = createContext(undefined); @@ -31,7 +31,7 @@ const chainsReducer = (state: State, action: Action): State => { return { ...state, chain: action.payload, - validatorState: { validators: [], status: "initial" }, + validatorState: { validators: emptyAllValidatorsEmpty(), status: "initial" }, }; } case "addNodeAddress": { @@ -66,7 +66,7 @@ export const ChainsProvider = ({ children }: ChainsProviderProps) => { chain: emptyChain, chains: { mainnets: new Map(), testnets: new Map(), localnets: new Map() }, newConnection: { action: "edit" }, - validatorState: { validators: [], status: "initial" }, + validatorState: { validators: emptyAllValidatorsEmpty(), status: "initial" }, }); const { chainItems, chainItemsError } = useChainsFromRegistry(); @@ -105,7 +105,7 @@ export const ChainsProvider = ({ children }: ChainsProviderProps) => { description: "Failed to load validators", fullError: e instanceof Error ? e : undefined, }); - dispatch({ type: "setValidatorState", payload: { validators: [], status: "error" } }); + dispatch({ type: "setValidatorState", payload: { validators: emptyAllValidatorsEmpty(), status: "error" } }); } } })(); @@ -114,7 +114,7 @@ export const ChainsProvider = ({ children }: ChainsProviderProps) => { return {children}; }; -export const useChains = () => { +export const useChains = (): State & { chainsDispatch: Dispatch } => { const context = useContext(ChainsContext); if (context === undefined) { throw new Error("useChains must be used within a ChainsProvider"); diff --git a/context/ChainsContext/types.tsx b/context/ChainsContext/types.tsx index 20bf452..5d5f1ca 100644 --- a/context/ChainsContext/types.tsx +++ b/context/ChainsContext/types.tsx @@ -1,5 +1,5 @@ -import { Validator } from "cosmjs-types/cosmos/staking/v1beta1/staking"; import { RegistryAsset } from "../../types/chainRegistry"; +import { AllValidators } from "@/lib/staking"; export interface ChainsContextType { readonly state: State; @@ -39,7 +39,7 @@ export interface ChainInfo { } export interface ValidatorState { - readonly validators: readonly Validator[]; + readonly validators: AllValidators; readonly status: "initial" | "loading" | "done" | "error"; } diff --git a/lib/staking.ts b/lib/staking.ts index 217dc56..01e4a9a 100644 --- a/lib/staking.ts +++ b/lib/staking.ts @@ -2,24 +2,68 @@ import { QueryClient, StakingExtension, setupStakingExtension } from "@cosmjs/st import { connectComet } from "@cosmjs/tendermint-rpc"; import { Validator } from "cosmjs-types/cosmos/staking/v1beta1/staking"; -const getValidatorsPage = ( +const getBondedValidatorsPage = ( queryClient: QueryClient & StakingExtension, paginationKey: Uint8Array | undefined, ) => queryClient.staking.validators("BOND_STATUS_BONDED", paginationKey); -export const getAllValidators = async (rpcUrl: string): Promise => { - const validators: Validator[] = []; +const getUnbondingValidatorsPage = ( + queryClient: QueryClient & StakingExtension, + paginationKey: Uint8Array | undefined, +) => queryClient.staking.validators("BOND_STATUS_UNBONDING", paginationKey); + +const getUnbondedValidatorsPage = ( + queryClient: QueryClient & StakingExtension, + paginationKey: Uint8Array | undefined, +) => queryClient.staking.validators("BOND_STATUS_UNBONDED", paginationKey); + +export interface AllValidators { + bonded: readonly Validator[]; + unbonding: readonly Validator[]; + unbonded: readonly Validator[]; +} + +export function emptyAllValidatorsEmpty(): AllValidators { + return { bonded: [], unbonding: [], unbonded: [] }; +} + +export const getAllValidators = async (rpcUrl: string): Promise => { + const bondedValidators: Validator[] = []; + const unbondingValidators: Validator[] = []; + const unbondedValidators: Validator[] = []; const cometClient = await connectComet(rpcUrl); const queryClient = QueryClient.withExtensions(cometClient, setupStakingExtension); - let paginationKey: Uint8Array | undefined = undefined; + let paginationKey: Uint8Array | undefined; + // Bonded + paginationKey = undefined; do { - const response = await getValidatorsPage(queryClient, paginationKey); - validators.push(...response.validators); + const response = await getBondedValidatorsPage(queryClient, paginationKey); + bondedValidators.push(...response.validators); paginationKey = response.pagination?.nextKey; } while (paginationKey?.length); - return validators; + // Unbonding + paginationKey = undefined; + do { + const response = await getUnbondingValidatorsPage(queryClient, paginationKey); + unbondingValidators.push(...response.validators); + paginationKey = response.pagination?.nextKey; + } while (paginationKey?.length); + + // Unbonded + paginationKey = undefined; + do { + const response = await getUnbondedValidatorsPage(queryClient, paginationKey); + unbondedValidators.push(...response.validators); + paginationKey = response.pagination?.nextKey; + } while (paginationKey?.length); + + return { + bonded: bondedValidators, + unbonding: unbondingValidators, + unbonded: unbondedValidators, + }; };