diff --git a/apps/namadillo/package.json b/apps/namadillo/package.json index 321a2c2de..5d2a3ebd6 100644 --- a/apps/namadillo/package.json +++ b/apps/namadillo/package.json @@ -7,7 +7,7 @@ "license": "MIT", "private": true, "dependencies": { - "@anomaorg/namada-indexer-client": "../../../namada-indexer-client", + "@anomaorg/namada-indexer-client": "0.0.23", "@cosmjs/encoding": "^0.32.3", "@tailwindcss/container-queries": "^0.1.1", "@tanstack/react-query": "^5.40.0", diff --git a/apps/namadillo/src/App/Governance/ProposalHeader.tsx b/apps/namadillo/src/App/Governance/ProposalHeader.tsx index 314ae66e4..b50e9fdee 100644 --- a/apps/namadillo/src/App/Governance/ProposalHeader.tsx +++ b/apps/namadillo/src/App/Governance/ProposalHeader.tsx @@ -296,7 +296,9 @@ const VoteButton: React.FC<{ }> = ({ proposal, voted, proposalId }) => { const navigate = useNavigate(); const isExtensionConnected = useAtomValue(namadaExtensionConnectedAtom); - const canVote = useAtomValue(canVoteAtom); + const canVote = useAtomValue( + canVoteAtom(proposal.data?.startEpoch || BigInt(-1)) + ); if (!isExtensionConnected) { return null; diff --git a/apps/namadillo/src/App/Governance/ProposalStatusSummary.tsx b/apps/namadillo/src/App/Governance/ProposalStatusSummary.tsx index 5b51f2473..25a902df6 100644 --- a/apps/namadillo/src/App/Governance/ProposalStatusSummary.tsx +++ b/apps/namadillo/src/App/Governance/ProposalStatusSummary.tsx @@ -1,7 +1,7 @@ import BigNumber from "bignumber.js"; import clsx from "clsx"; import { AnimatePresence, motion } from "framer-motion"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import { PieChart, PieChartData, Stack } from "@namada/components"; import { formatPercentage } from "@namada/utils"; @@ -165,6 +165,11 @@ const Loaded: React.FC<{ highestVoteType ); + useEffect(() => { + // Reset the hovered vote type when the highest vote type changes(on data poll) + setHoveredVoteType(highestVoteType); + }, [highestVoteType]); + const votedProportion = totalVotingPower.isEqualTo(0) ? BigNumber(0) diff --git a/apps/namadillo/src/App/Governance/SubmitVote.tsx b/apps/namadillo/src/App/Governance/SubmitVote.tsx index 546d32372..f373c5f67 100644 --- a/apps/namadillo/src/App/Governance/SubmitVote.tsx +++ b/apps/namadillo/src/App/Governance/SubmitVote.tsx @@ -73,11 +73,12 @@ export const WithProposalId: React.FC<{ proposalId: bigint }> = ({ const [selectedVoteType, setSelectedVoteType] = useState(); const proposalQueryResult = useAtomValue(proposalFamily(proposalId)); - const canVote = useAtomValue(canVoteAtom); const proposal = proposalQueryResult.isSuccess ? proposalQueryResult.data : null; + const canVote = useAtomValue(canVoteAtom(proposal?.startEpoch || BigInt(-1))); + const onCloseModal = (): void => navigate(-1); const dispatchPendingNotification = (txs: TxProps[]): void => { diff --git a/apps/namadillo/src/atoms/etc.ts b/apps/namadillo/src/atoms/etc.ts index e3e2f615d..c27577ce0 100644 --- a/apps/namadillo/src/atoms/etc.ts +++ b/apps/namadillo/src/atoms/etc.ts @@ -6,6 +6,7 @@ import { atomWithStorage } from "jotai/utils"; type ControlRoutineProps = { shouldUpdateAmount: boolean; + shouldUpdateProposal: boolean; lastBlockHeight: BigNumber | undefined; }; @@ -13,6 +14,7 @@ export const controlRoutineAtom = atomWithStorage( "namadillo:etc", { shouldUpdateAmount: false, + shouldUpdateProposal: false, lastBlockHeight: undefined, } ); @@ -29,7 +31,12 @@ export const shouldUpdateBalanceAtom = atom( changeProps("shouldUpdateAmount") ); +export const shouldUpdateProposalAtom = atom( + (get) => get(controlRoutineAtom).shouldUpdateProposal, + changeProps("shouldUpdateProposal") +); + export const lastBlockHeightAtom = atom( - (get) => get(controlRoutineAtom).shouldUpdateAmount, + (get) => get(controlRoutineAtom).lastBlockHeight, changeProps("lastBlockHeight") ); diff --git a/apps/namadillo/src/atoms/proposals/atoms.ts b/apps/namadillo/src/atoms/proposals/atoms.ts index de5756839..951d4165a 100644 --- a/apps/namadillo/src/atoms/proposals/atoms.ts +++ b/apps/namadillo/src/atoms/proposals/atoms.ts @@ -21,15 +21,16 @@ import { fetchVotedProposalIds, } from "./functions"; -import { - Bond as NamadaIndexerBond, - BondStatusEnum as NamadaIndexerBondStatusEnum, -} from "@anomaorg/namada-indexer-client"; +import { Bond as NamadaIndexerBond } from "@anomaorg/namada-indexer-client"; +import { shouldUpdateProposalAtom } from "atoms/etc"; export const proposalFamily = atomFamily((id: bigint) => atomWithQuery((get) => { const api = get(indexerApiAtom); + const enablePolling = get(shouldUpdateProposalAtom); return { + // TODO: subscribe to indexer events when it's done + refetchInterval: enablePolling ? 1000 : false, queryKey: ["proposal", id.toString()], queryFn: () => fetchProposalById(api, id), }; @@ -96,7 +97,11 @@ export const paginatedProposalsFamily = atomFamily( export const votedProposalIdsAtom = atomWithQuery((get) => { const account = get(defaultAccountAtom); const api = get(indexerApiAtom); + const enablePolling = get(shouldUpdateProposalAtom); + return { + // TODO: subscribe to indexer events when it's done + refetchInterval: enablePolling ? 1000 : false, queryKey: ["voted-proposal-ids", account.data], ...queryDependentFn(async () => { if (typeof account.data === "undefined") { @@ -107,25 +112,29 @@ export const votedProposalIdsAtom = atomWithQuery((get) => { }; }); -export const canVoteAtom = atomWithQuery((get) => { - const account = get(defaultAccountAtom); - const api = get(indexerApiAtom); +export const canVoteAtom = atomFamily((proposalStartEpoch: bigint) => + atomWithQuery((get) => { + const account = get(defaultAccountAtom); + const api = get(indexerApiAtom); - return { - queryKey: ["can-vote"], - enabled: account.isSuccess, - queryFn: async () => { - const all_bonds = await api.apiV1PosBondAddressGet(account.data!.address); + return { + queryKey: ["can-vote"], + enabled: account.isSuccess, + queryFn: async () => { + const all_bonds = await api.apiV1PosBondAddressGet( + account.data!.address + ); - return all_bonds.data.results.reduce( - (acc: boolean, current: NamadaIndexerBond) => { - return acc || current.status === NamadaIndexerBondStatusEnum.Active; - }, - false - ); - }, - }; -}); + return all_bonds.data.results.reduce( + (acc: boolean, current: NamadaIndexerBond) => { + return acc || Number(current.startEpoch) <= proposalStartEpoch; + }, + false + ); + }, + }; + }) +); type CreateVoteTxArgs = { proposalId: bigint; diff --git a/apps/namadillo/src/atoms/validators/functions.ts b/apps/namadillo/src/atoms/validators/functions.ts index e2c2d2643..4e2f1b18c 100644 --- a/apps/namadillo/src/atoms/validators/functions.ts +++ b/apps/namadillo/src/atoms/validators/functions.ts @@ -1,5 +1,6 @@ import { Bond as IndexerBond, + MergedBond as IndexerMergedBond, Unbond as IndexerUnbond, Validator as IndexerValidator, VotingPower as IndexerVotingPower, @@ -61,7 +62,7 @@ export const calculateUnbondingTimeLeft = (unbond: IndexerUnbond): string => { * an array of MyValidators objects */ export const toMyValidators = ( - indexerBonds: IndexerBond[], + indexerBonds: IndexerBond[] | IndexerMergedBond[], indexerUnbonds: IndexerUnbond[], totalVotingPower: IndexerVotingPower, epochInfo: EpochInfo, diff --git a/apps/namadillo/src/hooks/useTransactionCallbacks.tsx b/apps/namadillo/src/hooks/useTransactionCallbacks.tsx index a0d38a6d1..fc9ceedf5 100644 --- a/apps/namadillo/src/hooks/useTransactionCallbacks.tsx +++ b/apps/namadillo/src/hooks/useTransactionCallbacks.tsx @@ -1,11 +1,13 @@ import { accountBalanceAtom } from "atoms/accounts"; -import { shouldUpdateBalanceAtom } from "atoms/etc"; -import { useAtomValue, useSetAtom } from "jotai"; +import { shouldUpdateBalanceAtom, shouldUpdateProposalAtom } from "atoms/etc"; +import { proposalFamily, votedProposalIdsAtom } from "atoms/proposals"; +import { createStore, useAtomValue, useSetAtom } from "jotai"; import { useTransactionEventListener } from "utils"; export const useTransactionCallback = (): void => { const { refetch: refetchBalances } = useAtomValue(accountBalanceAtom); const shouldUpdateBalance = useSetAtom(shouldUpdateBalanceAtom); + const shouldUpdateProposal = useSetAtom(shouldUpdateProposalAtom); const onBalanceUpdate = (): void => { // TODO: refactor this after event subscription is enabled on indexer @@ -19,4 +21,27 @@ export const useTransactionCallback = (): void => { useTransactionEventListener("Bond.Success", onBalanceUpdate); useTransactionEventListener("Unbond.Success", onBalanceUpdate); useTransactionEventListener("Withdraw.Success", onBalanceUpdate); + + const store = createStore(); + + useTransactionEventListener("VoteProposal.Success", (args) => { + // TODO: refactor this after event subscription is enabled on indexer + shouldUpdateProposal(true); + + // [0] is fine for time being as we can only vote for one proposal at a time + const proposalId = args.detail.data[0].proposalId; + const { refetch: refetchProposalFamily } = store.get( + proposalFamily(proposalId) + ); + refetchProposalFamily(); + + const { refetch: refetchVotedProposalIds } = + store.get(votedProposalIdsAtom); + refetchVotedProposalIds(); + + // This does not guarantee that the proposal will be updated, + // but because this is temporary solution(don't quote me on this), it should be fine :) + const timePolling = 12 * 1000; + setTimeout(() => shouldUpdateProposal(false), timePolling); + }); }; diff --git a/yarn.lock b/yarn.lock index 186cd0d61..7fc6f8e61 100644 --- a/yarn.lock +++ b/yarn.lock @@ -45,12 +45,12 @@ __metadata: languageName: node linkType: hard -"@anomaorg/namada-indexer-client@file:../../../namada-indexer-client::locator=%40namada%2Fnamadillo%40workspace%3Aapps%2Fnamadillo": - version: 0.0.22 - resolution: "@anomaorg/namada-indexer-client@file:../../../namada-indexer-client#../../../namada-indexer-client::hash=3a5fbb&locator=%40namada%2Fnamadillo%40workspace%3Aapps%2Fnamadillo" +"@anomaorg/namada-indexer-client@npm:0.0.23": + version: 0.0.23 + resolution: "@anomaorg/namada-indexer-client@npm:0.0.23" dependencies: axios: "npm:^1.6.1" - checksum: 812376e1e7591f5f8f6a4a28c237797bf58aa7cf956f2a4cc373ad2bc4d270da5ec3c80b617a20d5e9c40a949a2d5f73873a08f410607caa426666d6418b3682 + checksum: 1249a851ad5ad09daa88bc621fbc33fe520a3f5912ab02d472c4d7b52f26fb83cee2f7818c634a55abb137dfdf5226d0ecd057e24895573199da069a5111e1cd languageName: node linkType: hard @@ -8448,7 +8448,7 @@ __metadata: version: 0.0.0-use.local resolution: "@namada/namadillo@workspace:apps/namadillo" dependencies: - "@anomaorg/namada-indexer-client": ../../../namada-indexer-client + "@anomaorg/namada-indexer-client": "npm:0.0.23" "@cosmjs/encoding": "npm:^0.32.3" "@playwright/test": "npm:^1.24.1" "@release-it/keep-a-changelog": "npm:^5.0.0"