diff --git a/examples/chain-template/components/voting/Voting.tsx b/examples/chain-template/components/voting/Voting.tsx index 5e142df5b..e5bbee40c 100644 --- a/examples/chain-template/components/voting/Voting.tsx +++ b/examples/chain-template/components/voting/Voting.tsx @@ -1,5 +1,5 @@ -import { useState } from 'react'; -import { useChain } from '@cosmos-kit/react'; +import { useEffect, useState } from "react"; +import { useChain } from "@cosmos-kit/react"; import { Proposal as IProposal, ProposalStatus, @@ -12,10 +12,11 @@ import { Spinner, Text, useColorModeValue, -} from '@interchain-ui/react'; -import { useModal, useVotingData } from '@/hooks'; -import { Proposal } from '@/components'; -import { formatDate } from '@/utils'; +} from "@interchain-ui/react"; +import { useModal, useVotingData } from "@/hooks"; +import { Proposal } from "@/components"; +import { formatDate } from "@/utils"; +import { chains } from 'chain-registry' function status(s: ProposalStatus) { switch (s) { @@ -38,10 +39,10 @@ function status(s: ProposalStatus) { function votes(result: TallyResult) { return { - yes: Number(result.yesCount) || 0, - no: Number(result.noCount) || 0, - abstain: Number(result.abstainCount) || 0, - noWithVeto: Number(result.noWithVetoCount) || 0, + yes: Number(result?.yesCount) || 0, + no: Number(result?.noCount) || 0, + abstain: Number(result?.abstainCount) || 0, + noWithVeto: Number(result?.noWithVetoCount) || 0, }; } @@ -53,7 +54,40 @@ export function Voting({ chainName }: VotingProps) { const { address } = useChain(chainName); const [proposal, setProposal] = useState(); const { data, isLoading, refetch } = useVotingData(chainName); - const { modal, open: openModal, close: closeModal, setTitle } = useModal(''); + const { modal, open: openModal, close: closeModal, setTitle } = useModal(""); + const [tallies, setTallies] = useState<{ [key: string]: TallyResult }>({}); + + const chain = chains.find((c) => c.chain_name === chainName); + + useEffect(() => { + if (!data.proposals || data.proposals.length === 0) return + data.proposals.forEach((proposal) => { + if (proposal.status === ProposalStatus.PROPOSAL_STATUS_VOTING_PERIOD) { + (async () => { + for (const { address } of chain?.apis?.rest || []) { + const api = `${address}/cosmos/gov/v1/proposals/${Number(proposal.id)}/tally` + try { + const tally = (await (await fetch(api)).json()).tally + if (!tally) { + continue + } + setTallies(prev => { + return { + ...prev, [proposal.id.toString()]: { + yesCount: tally.yes_count, + noCount: tally.no_count, + abstainCount: tally.abstain_count, + noWithVetoCount: tally.no_with_veto_count, + } + } + }) + break + } catch (e) { } + } + })() + } + }); + }, [data.proposals?.length, chainName]) function onClickProposal(index: number) { const proposal = data.proposals![index]; @@ -65,8 +99,12 @@ export function Voting({ chainName }: VotingProps) { const content = ( - {data.proposals?.map((proposal, index) => ( - { + let tally = proposal.finalTallyResult + if (proposal.status === ProposalStatus.PROPOSAL_STATUS_VOTING_PERIOD) { + tally = tallies[proposal.id.toString()] + } + return ( - - ))} + ) + })} ); diff --git a/examples/chain-template/config/chains.ts b/examples/chain-template/config/chains.ts index f263fe1a3..6177cb2e7 100644 --- a/examples/chain-template/config/chains.ts +++ b/examples/chain-template/config/chains.ts @@ -1,7 +1,7 @@ import { chains } from 'chain-registry'; import osmosis from 'chain-registry/mainnet/osmosis/chain'; -const chainNames = ['osmosistestnet', 'juno', 'stargaze', 'osmosis']; +const chainNames = ['osmosistestnet', 'juno', 'stargaze', 'osmosis', 'cosmoshub']; export const chainOptions = chainNames.map( (chainName) => chains.find((chain) => chain.chain_name === chainName)! diff --git a/examples/chain-template/hooks/voting/useVotingData.ts b/examples/chain-template/hooks/voting/useVotingData.ts index 071d46f98..aae05fd1b 100644 --- a/examples/chain-template/hooks/voting/useVotingData.ts +++ b/examples/chain-template/hooks/voting/useVotingData.ts @@ -1,10 +1,11 @@ import { useEffect, useMemo, useState } from 'react'; import { useChain } from '@cosmos-kit/react'; import { useQueries } from '@tanstack/react-query'; -import { Proposal, ProposalStatus } from 'interchain-query/cosmos/gov/v1beta1/gov'; +import { ProposalStatus } from 'interchain-query/cosmos/gov/v1beta1/gov'; import { Proposal as ProposalV1 } from 'interchain-query/cosmos/gov/v1/gov'; import { useQueryHooks, useRpcQueryClient } from '.'; import { getTitle, paginate, parseQuorum } from '@/utils'; +import { chains } from 'chain-registry' (BigInt.prototype as any).toJSON = function () { return this.toString(); @@ -39,8 +40,7 @@ export function useVotingData(chainName: string) { const { address } = useChain(chainName); const { rpcQueryClient } = useRpcQueryClient(chainName); const { cosmos, isReady, isFetching } = useQueryHooks(chainName); - - // cosmos.gov.v1.useProposals + const chain = chains.find((c) => c.chain_name === chainName); const proposalsQuery = cosmos.gov.v1.useProposals({ request: { @@ -146,9 +146,36 @@ export function useVotingData(chainName: string) { const singleQueriesData = useMemo(() => { if (isStaticQueriesFetching || !isReady) return; - return Object.fromEntries( + const singleQueriesData = Object.fromEntries( Object.entries(singleQueries).map(([key, query]) => [key, query.data]) ) as SingleQueriesData; + + singleQueriesData?.proposals.forEach((proposal) => { + if (proposal.status === ProposalStatus.PROPOSAL_STATUS_VOTING_PERIOD) { + (async () => { + for (const { address } of chain?.apis?.rest || []) { + const api = `${address}/cosmos/gov/v1/proposals/${Number(proposal.id)}/tally` + try { + const tally = (await (await fetch(api)).json()).tally + if (!tally) { + continue + } + proposal.finalTallyResult = { + yesCount: tally.yes_count, + noCount: tally.no_count, + abstainCount: tally.abstain_count, + noWithVetoCount: tally.no_with_veto_count, + } + break + } catch (e) { + console.error('error fetch tally', api) + } + } + })() + } + }) + + return singleQueriesData }, [isStaticQueriesFetching, isReady]); const votes = useMemo(() => { diff --git a/examples/chain-template/package.json b/examples/chain-template/package.json index 7d93fcd46..ebd9392b9 100644 --- a/examples/chain-template/package.json +++ b/examples/chain-template/package.json @@ -25,7 +25,7 @@ "@cosmjs/cosmwasm-stargate": "0.32.3", "@cosmjs/stargate": "0.31.1", "@cosmos-kit/react": "2.18.0", - "@interchain-ui/react": "1.23.29", + "@interchain-ui/react": "1.23.31", "@interchain-ui/react-no-ssr": "0.1.2", "@tanstack/react-query": "4.32.0", "ace-builds": "1.35.0", diff --git a/examples/chain-template/utils/voting.ts b/examples/chain-template/utils/voting.ts index 4759cde8e..38ca488de 100644 --- a/examples/chain-template/utils/voting.ts +++ b/examples/chain-template/utils/voting.ts @@ -12,7 +12,7 @@ export function getChainLogo(chain: Chain) { export function formatDate(date?: Date) { if (!date) return null; - return dayjs(date).format('YYYY-MM-DD hh:mm:ss'); + return dayjs(date).format('YYYY-MM-DD HH:mm:ss'); } export function paginate(limit: bigint, reverse: boolean = false) { @@ -28,10 +28,10 @@ export function paginate(limit: bigint, reverse: boolean = false) { export function percent(num: number | string = 0, total: number, decimals = 2) { return total ? new BigNumber(num) - .dividedBy(total) - .multipliedBy(100) - .decimalPlaces(decimals) - .toNumber() + .dividedBy(total) + .multipliedBy(100) + .decimalPlaces(decimals) + .toNumber() : 0; } diff --git a/examples/chain-template/yarn.lock b/examples/chain-template/yarn.lock index 358fbae36..407cd5402 100644 --- a/examples/chain-template/yarn.lock +++ b/examples/chain-template/yarn.lock @@ -813,7 +813,7 @@ __metadata: "@cosmjs/cosmwasm-stargate": "npm:0.32.3" "@cosmjs/stargate": "npm:0.31.1" "@cosmos-kit/react": "npm:2.18.0" - "@interchain-ui/react": "npm:1.23.29" + "@interchain-ui/react": "npm:1.23.31" "@interchain-ui/react-no-ssr": "npm:0.1.2" "@keplr-wallet/types": "npm:^0.12.111" "@starship-ci/cli": "npm:^2.9.0" @@ -2098,9 +2098,9 @@ __metadata: languageName: node linkType: hard -"@interchain-ui/react@npm:1.23.29": - version: 1.23.29 - resolution: "@interchain-ui/react@npm:1.23.29" +"@interchain-ui/react@npm:1.23.31": + version: 1.23.31 + resolution: "@interchain-ui/react@npm:1.23.31" dependencies: "@floating-ui/core": "npm:^1.6.4" "@floating-ui/dom": "npm:^1.6.7" @@ -2129,7 +2129,7 @@ __metadata: peerDependencies: react: ^16.14.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.14.0 || ^17.0.0 || ^18.0.0 - checksum: 10c0/013d8f56f0db143bc76f7e6f2509aab4ebb249a770e615df77b29748b07e743fff850d6a4599cbacc98ba7c047947e583eeb8e892f5796358243a37eb6d772d2 + checksum: 10c0/b8ec3c81035651de08958aeb1497e423e02643f2b1e3fc1fc80b09396f017b2769e94de3b1f6cb44ef9852d8fa8ac890d82e86c23291a029961332000cccc2de languageName: node linkType: hard