Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions pages/governance/v3/proposal/index.governance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,7 @@ export default function ProposalPage() {
error: proposalError,
} = useGovernanceProposalDetail(proposalId);

// For graph path, get votingChainId from rawProposal
const votingChainId = proposal?.rawProposal
? +proposal.rawProposal.subgraphProposal.votingPortal.votingMachineChainId
: undefined;
const votingChainId = proposal?.voteProposalData?.votingMachineChainId;

const voters = useGovernanceVotersSplit(proposalId, votingChainId);
const { data: payloads, isLoading: payloadsLoading } = useProposalPayloadsCache(proposalId);
Expand All @@ -62,7 +59,7 @@ export default function ProposalPage() {
/>
</Grid>
<Grid item xs={12} md={4}>
{proposal?.rawProposal && <VoteInfo proposal={proposal.rawProposal} />}
{proposal?.voteProposalData && <VoteInfo voteData={proposal.voteProposalData} />}
<VotingResults
proposal={proposal}
voters={voters}
Expand Down
28 changes: 22 additions & 6 deletions src/components/transactions/GovVote/GovVoteActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import { AbiCoder, keccak256, RLP } from 'ethers/lib/utils';
import { useState } from 'react';
import { MOCK_SIGNED_HASH } from 'src/helpers/useTransactionHandler';
import { useGovernanceTokensAndPowers } from 'src/hooks/governance/useGovernanceTokensAndPowers';
import { Proposal } from 'src/hooks/governance/useProposals';
import { useModalContext } from 'src/hooks/useModal';
import { useWeb3Context } from 'src/libs/hooks/useWeb3Context';
import { VoteProposalData } from 'src/modules/governance/types';
import { useRootStore } from 'src/store/root';
import { governanceV3Config } from 'src/ui-config/governanceConfig';
import { getProvider } from 'src/utils/marketsAndNetworksConfig';
Expand Down Expand Up @@ -55,7 +55,7 @@ export type AssetsBalanceSlots = Record<
export type GovVoteActionsProps = {
isWrongNetwork: boolean;
blocked: boolean;
proposal: Proposal;
proposal: VoteProposalData;
support: boolean;
};

Expand Down Expand Up @@ -201,11 +201,11 @@ export const GovVoteActions = ({
const { sendTx, signTxData } = useWeb3Context();
const queryClient = useQueryClient();

const tokenPowers = useGovernanceTokensAndPowers(proposal.subgraphProposal.snapshotBlockHash);
const tokenPowers = useGovernanceTokensAndPowers(proposal.snapshotBlockHash);
const [signature, setSignature] = useState<string | undefined>(undefined);
const proposalId = +proposal.subgraphProposal.id;
const blockHash = proposal.subgraphProposal.snapshotBlockHash;
const votingChainId = +proposal.subgraphProposal.votingPortal.votingMachineChainId;
const proposalId = +proposal.proposalId;
const blockHash = proposal.snapshotBlockHash;
const votingChainId = proposal.votingMachineChainId;
const votingMachineAddress =
governanceV3Config.votingChainConfig[votingChainId].votingMachineAddress;

Expand Down Expand Up @@ -267,7 +267,16 @@ export const GovVoteActions = ({
success: true,
});
queryClient.invalidateQueries({ queryKey: ['governance_proposal', proposalId, user] });
queryClient.invalidateQueries({
queryKey: ['governance-detail-cache', proposalId, user],
});
queryClient.invalidateQueries({ queryKey: ['proposalVotes', proposalId] });
queryClient.invalidateQueries({
queryKey: ['governance-voters-cache-for', proposalId],
});
queryClient.invalidateQueries({
queryKey: ['governance-voters-cache-against', proposalId],
});
return;
} else {
setTimeout(checkForStatus, 5000);
Expand All @@ -293,7 +302,14 @@ export const GovVoteActions = ({
});

queryClient.invalidateQueries({ queryKey: ['governance_proposal', proposalId, user] });
queryClient.invalidateQueries({ queryKey: ['governance-detail-cache', proposalId, user] });
queryClient.invalidateQueries({ queryKey: ['proposalVotes', proposalId] });
queryClient.invalidateQueries({
queryKey: ['governance-voters-cache-for', proposalId],
});
queryClient.invalidateQueries({
queryKey: ['governance-voters-cache-against', proposalId],
});
}
} catch (err) {
setMainTxState({
Expand Down
6 changes: 3 additions & 3 deletions src/components/transactions/GovVote/GovVoteModalContent.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Trans } from '@lingui/macro';
import { Box, Button, Typography, useTheme } from '@mui/material';
import { Proposal } from 'src/hooks/governance/useProposals';
import { useModalContext } from 'src/hooks/useModal';
import { useWeb3Context } from 'src/libs/hooks/useWeb3Context';
import { VoteProposalData } from 'src/modules/governance/types';
import { useRootStore } from 'src/store/root';
import { AIP } from 'src/utils/events';
import { getNetworkConfig } from 'src/utils/marketsAndNetworksConfig';
Expand All @@ -17,7 +17,7 @@ import { ChangeNetworkWarning } from '../Warnings/ChangeNetworkWarning';
import { GovVoteActions } from './GovVoteActions';

export type GovVoteModalContentProps = {
proposal: Proposal;
proposal: VoteProposalData;
support: boolean;
power: string;
};
Expand Down Expand Up @@ -63,7 +63,7 @@ export const GovVoteModalContent = ({
}
};

const proposalVotingChain = +proposal.subgraphProposal.votingPortal.votingMachineChainId;
const proposalVotingChain = proposal.votingMachineChainId;

const isWrongNetwork = connectedChainId !== proposalVotingChain;

Expand Down
74 changes: 61 additions & 13 deletions src/hooks/governance/useGovernanceProposals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
adaptGraphProposalToListItem,
} from 'src/modules/governance/adapters';
import { lifecycleToBadge } from 'src/modules/governance/StateBadge';
import { ProposalListItem, VotersSplitDisplay } from 'src/modules/governance/types';
import { ProposalListItem, VoteDisplay, VotersSplitDisplay } from 'src/modules/governance/types';
import {
getLifecycleState,
getProposalVoteInfo,
Expand All @@ -20,6 +20,7 @@ import {
getProposalDetailFromCache,
getProposalsFromCache,
getProposalVotesFromCache,
getUserVoteFromCache,
searchProposalsFromCache,
} from 'src/services/GovernanceCacheService';
import { useRootStore } from 'src/store/root';
Expand All @@ -41,6 +42,7 @@ const USE_GOVERNANCE_CACHE = process.env.NEXT_PUBLIC_USE_GOVERNANCE_CACHE === 't
const PAGE_SIZE = 10;
const VOTES_PAGE_SIZE = 50;
const SEARCH_RESULTS_LIMIT = 10;
export const ENS_REVERSE_REGISTRAR = '0x3671aE578E63FdF66ad4F3E12CC0c0d71Ac7510C';

// ============================================
// Subgraph search query
Expand Down Expand Up @@ -214,9 +216,12 @@ export const useGovernanceProposalDetail = (proposalId: number) => {
queryFn: async () => {
const detail = await getProposalDetailFromCache(String(proposalId));
if (!detail) return null;
return adaptCacheProposalToDetail(detail);

const userVote = user ? await getUserVoteFromCache(String(proposalId), user) : null;

return adaptCacheProposalToDetail(detail, userVote);
},
queryKey: ['governance-detail-cache', proposalId],
queryKey: ['governance-detail-cache', proposalId, user],
enabled: USE_GOVERNANCE_CACHE && !isNaN(proposalId),
refetchOnMount: false,
refetchOnReconnect: false,
Expand Down Expand Up @@ -331,7 +336,7 @@ export const useGovernanceVotersSplit = (
const votes = await fetchSubgraphVotes(proposalId, votingChainId as ChainId);
try {
const provider = getProvider(governanceV3Config.coreChainId);
const contract = new Contract('0x3671aE578E63FdF66ad4F3E12CC0c0d71Ac7510C', ensAbi);
const contract = new Contract(ENS_REVERSE_REGISTRAR, ensAbi);
const connectedContract = contract.connect(provider);
const ensNames: string[] = await connectedContract.getNames(votes.map((v) => v.voter));
return votes.map((vote, i) => ({
Expand All @@ -349,9 +354,44 @@ export const useGovernanceVotersSplit = (
refetchOnReconnect: false,
});

// ENS resolution for cache path voters
const cacheVoterAddresses = USE_GOVERNANCE_CACHE
? [
...(cacheForData?.pages.flatMap((p) => p.votes.map((v) => v.voter)) || []),
...(cacheAgainstData?.pages.flatMap((p) => p.votes.map((v) => v.voter)) || []),
]
: [];

const { data: cacheEnsNames } = useQuery({
queryFn: async () => {
const provider = getProvider(governanceV3Config.coreChainId);
const contract = new Contract(ENS_REVERSE_REGISTRAR, ensAbi);
const connectedContract = contract.connect(provider);
const names: string[] = await connectedContract.getNames(cacheVoterAddresses);
const map: Record<string, string> = {};
cacheVoterAddresses.forEach((addr, i) => {
if (names[i]) map[addr.toLowerCase()] = names[i];
});
return map;
},
queryKey: ['governance-voters-ens', proposalId, cacheVoterAddresses.length],
enabled: USE_GOVERNANCE_CACHE && cacheVoterAddresses.length > 0,
refetchOnMount: false,
refetchOnWindowFocus: false,
refetchOnReconnect: false,
});

if (USE_GOVERNANCE_CACHE) {
const yaeVotes = cacheForData?.pages.flatMap((p) => p.votes.map(adaptCacheVote)) || [];
const nayVotes = cacheAgainstData?.pages.flatMap((p) => p.votes.map(adaptCacheVote)) || [];
const withEns = (vote: VoteDisplay): VoteDisplay => ({
...vote,
ensName: cacheEnsNames?.[vote.voter.toLowerCase()],
});
const yaeVotes = (cacheForData?.pages.flatMap((p) => p.votes.map(adaptCacheVote)) || []).map(
withEns
);
const nayVotes = (
cacheAgainstData?.pages.flatMap((p) => p.votes.map(adaptCacheVote)) || []
).map(withEns);
const combinedVotes = [...yaeVotes, ...nayVotes].sort(
(a, b) => parseFloat(b.votingPower) - parseFloat(a.votingPower)
);
Expand All @@ -366,21 +406,29 @@ export const useGovernanceVotersSplit = (
const sortByPower = (a: { votingPower: string }, b: { votingPower: string }) =>
+a.votingPower < +b.votingPower ? 1 : +a.votingPower > +b.votingPower ? -1 : 0;

const toVoteDisplay = (v: {
voter: string;
support: boolean;
votingPower: string;
ensName?: string;
}): VoteDisplay => ({
voter: v.voter,
support: v.support,
votingPower: v.votingPower,
ensName: v.ensName,
});

const yaeVotes =
graphVotes
?.filter((v) => v.support)
.sort(sortByPower)
.map((v) => ({ voter: v.voter, support: v.support, votingPower: v.votingPower })) || [];
.map(toVoteDisplay) || [];
const nayVotes =
graphVotes
?.filter((v) => !v.support)
.sort(sortByPower)
.map((v) => ({ voter: v.voter, support: v.support, votingPower: v.votingPower })) || [];
const combinedVotes = graphVotes
? [...graphVotes]
.sort(sortByPower)
.map((v) => ({ voter: v.voter, support: v.support, votingPower: v.votingPower }))
: [];
.map(toVoteDisplay) || [];
const combinedVotes = graphVotes ? [...graphVotes].sort(sortByPower).map(toVoteDisplay) : [];

return { yaeVotes, nayVotes, combinedVotes, isFetching: graphFetching };
};
4 changes: 3 additions & 1 deletion src/hooks/governance/useProposalVotes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { governanceV3Config } from 'src/ui-config/governanceConfig';
import { getProvider } from 'src/utils/marketsAndNetworksConfig';
import { subgraphRequest } from 'src/utils/subgraphRequest';

import { ENS_REVERSE_REGISTRAR } from './useGovernanceProposals';

export type ProposalVote = {
proposalId: string;
support: boolean;
Expand Down Expand Up @@ -71,7 +73,7 @@ const fetchProposalVotes = async (

const fetchProposalVotesEnsNames = async (addresses: string[]) => {
const provider = getProvider(governanceV3Config.coreChainId);
const contract = new Contract('0x3671aE578E63FdF66ad4F3E12CC0c0d71Ac7510C', abi);
const contract = new Contract(ENS_REVERSE_REGISTRAR, abi);
const connectedContract = contract.connect(provider);
return connectedContract.getNames(addresses) as Promise<string[]>;
};
Expand Down
9 changes: 4 additions & 5 deletions src/hooks/useModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@ import { ChainId, Stake } from '@aave/contract-helpers';
import { AaveV3Ethereum } from '@bgd-labs/aave-address-book';
import { createContext, PropsWithChildren, useContext, useState } from 'react';
import { useWeb3Context } from 'src/libs/hooks/useWeb3Context';
import { VoteProposalData } from 'src/modules/governance/types';
import { ActionName, SwapActionFields, TransactionHistoryItem } from 'src/modules/history/types';
import { useRootStore } from 'src/store/root';
import { TxErrorType } from 'src/ui-config/errorMapping';
import { GENERAL } from 'src/utils/events';

import { Proposal } from './governance/useProposals';

export enum ModalType {
Supply,
Withdraw,
Expand Down Expand Up @@ -50,7 +49,7 @@ export enum ModalType {

export interface ModalArgsType {
underlyingAsset?: string;
proposal?: Proposal;
proposal?: VoteProposalData;
support?: boolean;
power?: string;
icon?: string;
Expand Down Expand Up @@ -139,7 +138,7 @@ export interface ModalContextType<T extends ModalArgsType> {
openGovDelegation: () => void;
openRevokeGovDelegation: () => void;
openV3Migration: () => void;
openGovVote: (proposal: Proposal, support: boolean, power: string) => void;
openGovVote: (proposal: VoteProposalData, support: boolean, power: string) => void;
openSwitch: (underlyingAsset?: string, chainId?: number) => void;
openBridge: () => void;
openStakingMigrate: () => void;
Expand Down Expand Up @@ -392,7 +391,7 @@ export const ModalContextProvider: React.FC<PropsWithChildren> = ({ children })
openGovVote: (proposal, support, power) => {
trackEvent(GENERAL.OPEN_MODAL, {
modal: 'Vote',
proposalId: proposal.subgraphProposal.id,
proposalId: proposal.proposalId,
voteSide: support,
});
setType(ModalType.GovVote);
Expand Down
Loading
Loading