From 04b7fa21b0babaa767b883dab31b774caac6cae8 Mon Sep 17 00:00:00 2001 From: poomthiti Date: Thu, 22 Jun 2023 18:46:10 +0700 Subject: [PATCH 1/5] fix: add validator image resolver hook (add keybase as a fallback option) --- CHANGELOG.md | 1 + src/lib/components/ValidatorBadge.tsx | 33 ++++----- src/lib/gql/gql.ts | 12 ++-- src/lib/gql/graphql.ts | 10 +++ src/lib/pages/account-details/data.ts | 4 ++ src/lib/query/block.ts | 2 + src/lib/services/blockService.ts | 2 + src/lib/services/delegation.ts | 98 +++++++++++++++++---------- src/lib/services/validator.ts | 30 +++++++- src/lib/services/validatorService.ts | 26 ++++++- src/lib/types/validator.ts | 1 + 11 files changed, 158 insertions(+), 61 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 64b79fb7a..935246532 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Improvements +- [#402](https://github.com/alleslabs/celatone-frontend/pull/402) Add validator image resolver hook (add keybase as a fallback option) - [#386](https://github.com/alleslabs/celatone-frontend/pull/386) Handle uppercase address - [#382](https://github.com/alleslabs/celatone-frontend/pull/382) Add pool manager v15 msgs to tx details - [#371](https://github.com/alleslabs/celatone-frontend/pull/371) Refactor assign me component and fix color in redelegation page diff --git a/src/lib/components/ValidatorBadge.tsx b/src/lib/components/ValidatorBadge.tsx index 06c2e7367..6fe17edf1 100644 --- a/src/lib/components/ValidatorBadge.tsx +++ b/src/lib/components/ValidatorBadge.tsx @@ -1,11 +1,9 @@ import type { ImageProps } from "@chakra-ui/react"; -import { Flex, Image, Text } from "@chakra-ui/react"; -import { useWallet } from "@cosmos-kit/react"; +import { Spinner, Flex, Image, Text } from "@chakra-ui/react"; -import { CURR_THEME, getChainApiPath } from "env"; import { ExplorerLink } from "lib/components/ExplorerLink"; +import { useValidatorImage } from "lib/services/validatorService"; import type { ValidatorInfo } from "lib/types"; -import { removeSpecialChars } from "lib/utils"; interface ValidatorBadgeProps { validator: ValidatorInfo | null; @@ -34,25 +32,22 @@ export const ValidatorBadge = ({ validator, badgeSize = 10, }: ValidatorBadgeProps) => { - const { currentChainName } = useWallet(); + const { data: valImgSrc, isLoading } = useValidatorImage(validator); + return ( {validator ? ( <> - {validator.moniker} + {isLoading ? ( + + ) : ( + {validator.moniker} + )} ; }; @@ -11813,6 +11814,7 @@ export type GetBlockDetailsByHeightQuery = { __typename?: "validators"; moniker: string; operator_address: string; + identity: string; } | null; } | null; }; @@ -12657,6 +12659,10 @@ export const GetBlockListQueryDocument = { kind: "Field", name: { kind: "Name", value: "operator_address" }, }, + { + kind: "Field", + name: { kind: "Name", value: "identity" }, + }, ], }, }, @@ -12762,6 +12768,10 @@ export const GetBlockDetailsByHeightDocument = { kind: "Field", name: { kind: "Name", value: "operator_address" }, }, + { + kind: "Field", + name: { kind: "Name", value: "identity" }, + }, ], }, }, diff --git a/src/lib/pages/account-details/data.ts b/src/lib/pages/account-details/data.ts index cffd2f385..49388ba8f 100644 --- a/src/lib/pages/account-details/data.ts +++ b/src/lib/pages/account-details/data.ts @@ -276,6 +276,7 @@ export const useUserDelegationInfos = (walletAddress: HumanAddr) => { validator: { validatorAddress: raw.validatorAddress, moniker: validators[raw.validatorAddress]?.moniker, + identity: raw.identity, }, token: coinToTokenWithValue(raw.denom, raw.amount, assetInfos[raw.denom]), })); @@ -296,6 +297,7 @@ export const useUserDelegationInfos = (walletAddress: HumanAddr) => { validator: { validatorAddress: raw.validatorAddress, moniker: validators[raw.validatorAddress]?.moniker, + identity: raw.identity, }, completionTime: raw.completionTime, token: coinToTokenWithValue( @@ -344,10 +346,12 @@ export const useUserDelegationInfos = (walletAddress: HumanAddr) => { srcValidator: { validatorAddress: raw.srcValidatorAddress, moniker: validators[raw.srcValidatorAddress]?.moniker, + identity: raw.srcIdentity, }, dstValidator: { validatorAddress: raw.dstValidatorAddress, moniker: validators[raw.dstValidatorAddress]?.moniker, + identity: raw.dstIdentity, }, completionTime: raw.completionTime, token: coinToTokenWithValue( diff --git a/src/lib/query/block.ts b/src/lib/query/block.ts index e961d9e27..69f9d483d 100644 --- a/src/lib/query/block.ts +++ b/src/lib/query/block.ts @@ -22,6 +22,7 @@ export const getBlockListQueryDocument = graphql(` validator { moniker operator_address + identity } } } @@ -44,6 +45,7 @@ export const getBlockDetailsByHeightQueryDocument = graphql(` validator { moniker operator_address + identity } } } diff --git a/src/lib/services/blockService.ts b/src/lib/services/blockService.ts index 7cf07c37f..57c894ba7 100644 --- a/src/lib/services/blockService.ts +++ b/src/lib/services/blockService.ts @@ -45,6 +45,7 @@ export const useBlocklistQuery = ( moniker: validator.moniker, validatorAddress: validator.operator_address as ValidatorAddr, + identity: validator.identity, } : null, }) @@ -94,6 +95,7 @@ export const useBlockDetailsQuery = ( moniker: blocks_by_pk.validator.moniker, validatorAddress: blocks_by_pk.validator .operator_address as ValidatorAddr, + identity: blocks_by_pk.validator.identity, } : null, } diff --git a/src/lib/services/delegation.ts b/src/lib/services/delegation.ts index 71c07444e..8c192caad 100644 --- a/src/lib/services/delegation.ts +++ b/src/lib/services/delegation.ts @@ -82,12 +82,14 @@ export interface RawStakingParams { export interface RawDelegation { validatorAddress: ValidatorAddr; + identity: string; denom: string; amount: string; } export interface RawUnbonding { validatorAddress: ValidatorAddr; + identity: string; completionTime: Date; amount: string; } @@ -104,7 +106,9 @@ export interface RawDelegationRewards { export interface RawRedelegation { srcValidatorAddress: ValidatorAddr; + srcIdentity: string; dstValidatorAddress: ValidatorAddr; + dstIdentity: string; completionTime: Date; amount: string; } @@ -133,14 +137,24 @@ export const getDelegations = async ( const { data } = await axios.get( `${endpoint}/cosmos/staking/v1beta1/delegations/${address}` ); - return data.delegation_responses - .map((delegation) => ({ - validatorAddress: delegation.delegation - .validator_address as ValidatorAddr, - denom: delegation.balance.denom, - amount: delegation.balance.amount, - })) - .sort((a, b) => big(b.amount).cmp(a.amount)); + return Promise.all( + data.delegation_responses.map>( + async (delegation) => { + const { data: valInfo } = await axios.get( + `${endpoint}/cosmos/staking/v1beta1/validators/${delegation.delegation.validator_address}` + ); + return { + validatorAddress: delegation.delegation + .validator_address as ValidatorAddr, + identity: valInfo.validator.description.identity as string, + denom: delegation.balance.denom, + amount: delegation.balance.amount, + }; + } + ) + ).then((delegations) => + delegations.sort((a, b) => big(b.amount).cmp(a.amount)) + ); }; export const getUnbondings = async ( @@ -150,19 +164,23 @@ export const getUnbondings = async ( const { data } = await axios.get( `${endpoint}/cosmos/staking/v1beta1/delegators/${address}/unbonding_delegations` ); - return data.unbonding_responses - .reduce( - (prev, validator) => - prev.concat( - ...validator.entries.map((entry) => ({ - validatorAddress: validator.validator_address as ValidatorAddr, - completionTime: parseDate(entry.completion_time), - amount: entry.balance, - })) - ), - [] - ) - .sort((a, b) => a.completionTime.getTime() - b.completionTime.getTime()); + return Promise.all( + data.unbonding_responses.map>(async (validator) => { + const { data: valInfo } = await axios.get( + `${endpoint}/cosmos/staking/v1beta1/validators/${validator.validator_address}` + ); + return validator.entries.map((entry) => ({ + validatorAddress: validator.validator_address as ValidatorAddr, + identity: valInfo.validator.description.identity as string, + completionTime: parseDate(entry.completion_time), + amount: entry.balance, + })); + }) + ).then((unbondings) => + unbondings + .flat() + .sort((a, b) => a.completionTime.getTime() - b.completionTime.getTime()) + ); }; export const getDelegationRewards = async ( @@ -188,20 +206,32 @@ export const getRedelegations = async ( const { data } = await axios.get( `${endpoint}/cosmos/staking/v1beta1/delegators/${address}/redelegations` ); - return data.redelegation_responses - .reduce( - (prev, redelegate) => - prev.concat( - ...redelegate.entries.map((entry) => ({ - srcValidatorAddress: redelegate.redelegation.validator_src_address, - dstValidatorAddress: redelegate.redelegation.validator_dst_address, - completionTime: parseDate(entry.redelegation_entry.completion_time), - amount: entry.balance, - })) - ), - [] + return Promise.all( + data.redelegation_responses.map>( + async (redelegate) => { + const [{ data: srcValInfo }, { data: dstValInfo }] = await Promise.all([ + axios.get( + `${endpoint}/cosmos/staking/v1beta1/validators/${redelegate.redelegation.validator_src_address}` + ), + axios.get( + `${endpoint}/cosmos/staking/v1beta1/validators/${redelegate.redelegation.validator_dst_address}` + ), + ]); + return redelegate.entries.map((entry) => ({ + srcValidatorAddress: redelegate.redelegation.validator_src_address, + srcIdentity: srcValInfo.validator.description.identity as string, + dstValidatorAddress: redelegate.redelegation.validator_dst_address, + dstIdentity: dstValInfo.validator.description.identity as string, + completionTime: parseDate(entry.redelegation_entry.completion_time), + amount: entry.balance, + })); + } ) - .sort((a, b) => a.completionTime.getTime() - b.completionTime.getTime()); + ).then((redelegations) => + redelegations + .flat() + .sort((a, b) => a.completionTime.getTime() - b.completionTime.getTime()) + ); }; export const getCommission = async ( diff --git a/src/lib/services/validator.ts b/src/lib/services/validator.ts index 5a33c8cd1..00b55d7e4 100644 --- a/src/lib/services/validator.ts +++ b/src/lib/services/validator.ts @@ -1,6 +1,8 @@ import axios from "axios"; -import type { ValidatorAddr } from "lib/types"; +import { CURR_THEME } from "env"; +import type { Option, ValidatorAddr, ValidatorInfo } from "lib/types"; +import { removeSpecialChars } from "lib/utils"; interface ValidatorsResponse { validators: { @@ -58,3 +60,29 @@ export const getValidators = async ( {} ); }; + +export const resolveValIdentity = async ( + apiPath: Option, + validator: ValidatorInfo +): Promise => { + const githubUrl = `https://raw.githubusercontent.com/cosmostation/chainlist/master/chain/${apiPath}/moniker/${validator.validatorAddress}.png`; + const keybaseUrl = `https://keybase.io/_/api/1.0/user/lookup.json?key_suffix=${validator.identity}&fields=pictures`; + const uiAvatarsUrl = `https://ui-avatars.com/api/?name=${removeSpecialChars( + validator.moniker ?? "" + )}&background=${CURR_THEME.colors.secondary.main.replace("#", "")}&color=fff`; + + return ( + axios + .get(githubUrl) + // eslint-disable-next-line @typescript-eslint/no-unused-vars + .then((_) => githubUrl) + // eslint-disable-next-line @typescript-eslint/no-unused-vars + .catch(async (_) => { + if (validator.identity) { + const { data } = await axios.get(keybaseUrl); + return data.them[0].pictures.primary.url; + } + return uiAvatarsUrl; + }) + ); +}; diff --git a/src/lib/services/validatorService.ts b/src/lib/services/validatorService.ts index f0d9ac20f..b502bfee6 100644 --- a/src/lib/services/validatorService.ts +++ b/src/lib/services/validatorService.ts @@ -1,11 +1,14 @@ +import { useWallet } from "@cosmos-kit/react"; import type { UseQueryResult } from "@tanstack/react-query"; import { useQuery } from "@tanstack/react-query"; import { useCallback } from "react"; +import { getChainApiPath } from "env"; import { useLCDEndpoint } from "lib/app-provider"; +import type { ValidatorInfo } from "lib/types"; import type { RawValidator } from "./validator"; -import { getValidators } from "./validator"; +import { resolveValIdentity, getValidators } from "./validator"; export const useValidators = (): UseQueryResult< Record @@ -19,3 +22,24 @@ export const useValidators = (): UseQueryResult< refetchOnWindowFocus: false, }); }; + +export const useValidatorImage = ( + validator: ValidatorInfo | null +): UseQueryResult => { + const { currentChainName } = useWallet(); + return useQuery({ + queryKey: [ + "query", + "validator_identity", + currentChainName, + validator?.validatorAddress, + ], + queryFn: async () => { + if (!validator) return Promise.resolve(""); + return resolveValIdentity(getChainApiPath(currentChainName), validator); + }, + retry: false, + refetchOnWindowFocus: false, + enabled: !!validator, + }); +}; diff --git a/src/lib/types/validator.ts b/src/lib/types/validator.ts index 65dde1455..607e7de9a 100644 --- a/src/lib/types/validator.ts +++ b/src/lib/types/validator.ts @@ -4,4 +4,5 @@ import type { Option } from "./common"; export interface ValidatorInfo { validatorAddress: ValidatorAddr; moniker: Option; + identity: string; } From 1643c93bb1ab9ee832679bfd7148ae55382d2831 Mon Sep 17 00:00:00 2001 From: poomthiti Date: Fri, 23 Jun 2023 15:13:44 +0700 Subject: [PATCH 2/5] feat: add fallback image --- public/validator.svg | 6 ++++++ src/lib/components/ValidatorBadge.tsx | 2 ++ 2 files changed, 8 insertions(+) create mode 100644 public/validator.svg diff --git a/public/validator.svg b/public/validator.svg new file mode 100644 index 000000000..fb754fce2 --- /dev/null +++ b/public/validator.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/lib/components/ValidatorBadge.tsx b/src/lib/components/ValidatorBadge.tsx index 6fe17edf1..e67ef37af 100644 --- a/src/lib/components/ValidatorBadge.tsx +++ b/src/lib/components/ValidatorBadge.tsx @@ -1,6 +1,7 @@ import type { ImageProps } from "@chakra-ui/react"; import { Spinner, Flex, Image, Text } from "@chakra-ui/react"; +import validatorDefaultImg from "../../../public/validator.svg"; import { ExplorerLink } from "lib/components/ExplorerLink"; import { useValidatorImage } from "lib/services/validatorService"; import type { ValidatorInfo } from "lib/types"; @@ -46,6 +47,7 @@ export const ValidatorBadge = ({ src={valImgSrc} alt={validator.moniker} borderRadius="50%" + fallbackSrc={validatorDefaultImg.src} /> )} Date: Tue, 4 Jul 2023 15:03:46 +0700 Subject: [PATCH 3/5] fix: replace lcd endpoint with celatone api and change fallback strategy --- src/lib/components/ExplorerLink.tsx | 4 ++-- src/lib/components/ValidatorBadge.tsx | 1 + src/lib/components/table/proposals/ProposalsTableRow.tsx | 4 ++-- src/lib/components/tx/modal/ButtonSection.tsx | 4 ++-- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/lib/components/ExplorerLink.tsx b/src/lib/components/ExplorerLink.tsx index 3db7411a1..93c90e3e8 100644 --- a/src/lib/components/ExplorerLink.tsx +++ b/src/lib/components/ExplorerLink.tsx @@ -4,8 +4,8 @@ import { Box, Text } from "@chakra-ui/react"; import type { ExplorerConfig } from "config/types"; import type { AddressReturnType } from "lib/app-provider"; import { useCelatoneApp } from "lib/app-provider/contexts"; +import { useBaseApiRoute } from "lib/app-provider/hooks/useBaseApiRoute"; import { useCurrentChain } from "lib/app-provider/hooks/useCurrentChain"; -import { useLCDEndpoint } from "lib/app-provider/hooks/useLCDEndpoint"; import { AmpTrackMintscan } from "lib/services/amplitude"; import type { Option } from "lib/types"; import { truncate } from "lib/utils"; @@ -159,7 +159,7 @@ export const ExplorerLink = ({ ...componentProps }: ExplorerLinkProps) => { const { address } = useCurrentChain(); - const lcdEndpoint = useLCDEndpoint(); + const lcdEndpoint = useBaseApiRoute("rest"); const { chainConfig: { explorerLink: explorerConfig }, } = useCelatoneApp(); diff --git a/src/lib/components/ValidatorBadge.tsx b/src/lib/components/ValidatorBadge.tsx index e67ef37af..e44262d0f 100644 --- a/src/lib/components/ValidatorBadge.tsx +++ b/src/lib/components/ValidatorBadge.tsx @@ -48,6 +48,7 @@ export const ValidatorBadge = ({ alt={validator.moniker} borderRadius="50%" fallbackSrc={validatorDefaultImg.src} + fallbackStrategy="onError" /> )} { const txHash = receipts From 46fd8bf28853057cb34e61c2f994bf940123886f Mon Sep 17 00:00:00 2001 From: poomthiti Date: Tue, 4 Jul 2023 15:13:06 +0700 Subject: [PATCH 4/5] refactor: remove space --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 0d68b88f9..6d14942ca 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,6 @@ /.pnp .pnp.js - # testing /coverage From 74642ef73bd7f03159cee1646c0853bc8861eaee Mon Sep 17 00:00:00 2001 From: evilpeach Date: Tue, 18 Jul 2023 15:21:39 +0700 Subject: [PATCH 5/5] chore: refactor --- CHANGELOG.md | 2 +- src/lib/services/delegation.ts | 30 +++++++++++++--------------- src/lib/services/validator.ts | 11 +++------- src/lib/services/validatorService.ts | 4 ++-- 4 files changed, 20 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 800bdf7cd..bff30c4dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Improvements +- [#402](https://github.com/alleslabs/celatone-frontend/pull/402) Add validator image resolver hook (add keybase as a fallback option) - [#431](https://github.com/alleslabs/celatone-frontend/pull/431) Add new Osmosis v16 tx messages - [#414](https://github.com/alleslabs/celatone-frontend/pull/414) Add jest test cases for funds and assetValue in utils, and remove isDecimalNumber in utils - [#435](https://github.com/alleslabs/celatone-frontend/pull/435) Refactor chain's config, add new chain configs @@ -80,7 +81,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Improvements -- [#402](https://github.com/alleslabs/celatone-frontend/pull/402) Add validator image resolver hook (add keybase as a fallback option) - [#428](https://github.com/alleslabs/celatone-frontend/pull/428) Get all validators from graphql - [#417](https://github.com/alleslabs/celatone-frontend/pull/417) Support responsive and add new theme - [#283](https://github.com/alleslabs/celatone-frontend/pull/283) Change unsupported token icon render logic diff --git a/src/lib/services/delegation.ts b/src/lib/services/delegation.ts index 8c192caad..9e35ebafa 100644 --- a/src/lib/services/delegation.ts +++ b/src/lib/services/delegation.ts @@ -5,6 +5,8 @@ import big from "big.js"; import type { Addr, Token, U, ValidatorAddr } from "lib/types"; import { parseDate, formatSeconds } from "lib/utils"; +import { getValidator } from "./validator"; + interface StakingParamsResponse { params: { unbonding_time: string; // e.g. "1209600s" @@ -140,13 +142,14 @@ export const getDelegations = async ( return Promise.all( data.delegation_responses.map>( async (delegation) => { - const { data: valInfo } = await axios.get( - `${endpoint}/cosmos/staking/v1beta1/validators/${delegation.delegation.validator_address}` + const valInfo = await getValidator( + endpoint, + delegation.delegation.validator_address ); return { validatorAddress: delegation.delegation .validator_address as ValidatorAddr, - identity: valInfo.validator.description.identity as string, + identity: valInfo.identity, denom: delegation.balance.denom, amount: delegation.balance.amount, }; @@ -166,12 +169,11 @@ export const getUnbondings = async ( ); return Promise.all( data.unbonding_responses.map>(async (validator) => { - const { data: valInfo } = await axios.get( - `${endpoint}/cosmos/staking/v1beta1/validators/${validator.validator_address}` - ); + const valInfo = await getValidator(endpoint, validator.validator_address); + return validator.entries.map((entry) => ({ validatorAddress: validator.validator_address as ValidatorAddr, - identity: valInfo.validator.description.identity as string, + identity: valInfo.identity, completionTime: parseDate(entry.completion_time), amount: entry.balance, })); @@ -209,19 +211,15 @@ export const getRedelegations = async ( return Promise.all( data.redelegation_responses.map>( async (redelegate) => { - const [{ data: srcValInfo }, { data: dstValInfo }] = await Promise.all([ - axios.get( - `${endpoint}/cosmos/staking/v1beta1/validators/${redelegate.redelegation.validator_src_address}` - ), - axios.get( - `${endpoint}/cosmos/staking/v1beta1/validators/${redelegate.redelegation.validator_dst_address}` - ), + const [srcValInfo, dstValInfo] = await Promise.all([ + getValidator(endpoint, redelegate.redelegation.validator_src_address), + getValidator(endpoint, redelegate.redelegation.validator_dst_address), ]); return redelegate.entries.map((entry) => ({ srcValidatorAddress: redelegate.redelegation.validator_src_address, - srcIdentity: srcValInfo.validator.description.identity as string, + srcIdentity: srcValInfo.identity, dstValidatorAddress: redelegate.redelegation.validator_dst_address, - dstIdentity: dstValInfo.validator.description.identity as string, + dstIdentity: dstValInfo.identity, completionTime: parseDate(entry.redelegation_entry.completion_time), amount: entry.balance, })); diff --git a/src/lib/services/validator.ts b/src/lib/services/validator.ts index 01174e301..7ae1a459a 100644 --- a/src/lib/services/validator.ts +++ b/src/lib/services/validator.ts @@ -1,12 +1,7 @@ import axios from "axios"; import { CURR_THEME } from "env"; -import type { - Option, - Validator, - ValidatorAddr, - ValidatorInfo, -} from "lib/types"; +import type { Validator, ValidatorAddr, ValidatorInfo } from "lib/types"; import { removeSpecialChars } from "lib/utils"; interface ValidatorResponse { @@ -54,10 +49,10 @@ export const getValidator = async ( }; export const resolveValIdentity = async ( - apiPath: Option, + chainName: string, validator: ValidatorInfo ): Promise => { - const githubUrl = `https://raw.githubusercontent.com/cosmostation/chainlist/master/chain/${apiPath}/moniker/${validator.validatorAddress}.png`; + const githubUrl = `https://raw.githubusercontent.com/cosmostation/chainlist/master/chain/${chainName}/moniker/${validator.validatorAddress}.png`; const keybaseUrl = `https://keybase.io/_/api/1.0/user/lookup.json?key_suffix=${validator.identity}&fields=pictures`; const uiAvatarsUrl = `https://ui-avatars.com/api/?name=${removeSpecialChars( validator.moniker ?? "" diff --git a/src/lib/services/validatorService.ts b/src/lib/services/validatorService.ts index 6a1e8c634..eddd82aa4 100644 --- a/src/lib/services/validatorService.ts +++ b/src/lib/services/validatorService.ts @@ -27,7 +27,7 @@ export const useValidator = ( ["query", "validator", lcdEndpoint, validatorAddr] as string[], queryFn, { - enabled: enabled && !!validatorAddr, + enabled: enabled && Boolean(validatorAddr), retry: 1, refetchOnWindowFocus: false, } @@ -80,6 +80,6 @@ export const useValidatorImage = ( }, retry: false, refetchOnWindowFocus: false, - enabled: !!validator, + enabled: Boolean(validator), }); };