Skip to content

Commit

Permalink
fix: added proposals list data polling
Browse files Browse the repository at this point in the history
  • Loading branch information
Argeare5 committed Nov 20, 2024
1 parent 75f9626 commit 2244eb9
Show file tree
Hide file tree
Showing 13 changed files with 700 additions and 198 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
"@wagmi/core": "^2.14.2",
"alova": "2.13.0",
"bignumber.js": "^9.1.2",
"bs58": "^6.0.0",
"dayjs": "^1.11.12",
"encoding": "^0.1.13",
"ethereum-blockies-base64": "^1.0.2",
Expand Down
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions src/components/ProposalsList/ProposalsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,18 @@ export function ProposalsList({
(store) => store.initializeProposalsListData,
);
const totalProposalsCount = useStore((store) => store.totalProposalsCount);
const startActiveProposalsDataPolling = useStore(
(store) => store.startActiveProposalsDataPolling,
);
const stopActiveProposalsDataPolling = useStore(
(store) => store.stopActiveProposalsDataPolling,
);
const startNewProposalsPolling = useStore(
(store) => store.startNewProposalsPolling,
);
const stopNewProposalsPolling = useStore(
(store) => store.stopNewProposalsPolling,
);
const proposalsListData = useStore((store) =>
selectProposalsForActivePage(store, activePage),
);
Expand All @@ -61,6 +73,14 @@ export function ProposalsList({
proposalsData.activeProposalsData.length,
proposalsData.finishedProposalsData.length,
]);
useEffect(() => {
startActiveProposalsDataPolling();
startNewProposalsPolling();
() => {
stopActiveProposalsDataPolling();
stopNewProposalsPolling();
};
}, []);

return (
<Container>
Expand Down
49 changes: 49 additions & 0 deletions src/requests/fetchActiveProposalsDataForList.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { Client } from 'viem';

import { ContractsConstants, VotingConfig } from '../types';
import { getDataForList } from './utils/getDataForList';
import { getPayloadsDataRPC } from './utils/getPayloadsDataRPC';
import { getProposalMetadata } from './utils/getProposalMetadata';
import { getProposalsDataRPC } from './utils/getProposalsDataRPC';

export type FetchProposalsDataForListParams = Pick<
ContractsConstants,
'precisionDivider' | 'expirationTime' | 'cooldownPeriod'
> & {
votingConfigs: VotingConfig[];
userAddress?: string;
representativeAddress?: string;
clients: Record<number, Client>;
activeIds: number[];
};

export async function fetchActiveProposalsDataForList({
input,
}: {
input: FetchProposalsDataForListParams;
}) {
try {
throw new Error('TODO: API not implemented');
} catch (e) {
console.error(
'Error getting proposals data from API, using RPC fallback',
e,
);
const proposalsData = await Promise.all(
(await getProposalsDataRPC({ ...input, proposalsIds: input.activeIds }))
.sort((a, b) => b.id - a.id)
.map(async (proposal) => {
return {
...proposal,
title: (await getProposalMetadata({ hash: proposal.ipfsHash }))
.title,
};
}),
);
return await getDataForList({
input,
proposals: proposalsData,
getPayloadsData: ({ ...props }) => getPayloadsDataRPC({ ...props }),
});
}
}
174 changes: 11 additions & 163 deletions src/requests/fetchProposalsDataForList.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,9 @@
import { IVotingPortal_ABI } from '@bgd-labs/aave-address-book/abis';
import { Client } from 'viem';
import { readContract } from 'viem/actions';

import { appConfig } from '../configs/appConfig';
import {
ContractsConstants,
InitialPayloadState,
InitialProposalState,
VotingConfig,
} from '../types';
import {
formatActiveProposalData,
getStateAndTimestampForFinishedProposal,
} from './utils/formatProposalData';
import { ContractsConstants, VotingConfig } from '../types';
import { getDataForList } from './utils/getDataForList';
import { getPayloadsData } from './utils/getPayloadsData';
import { GetProposalsData, getProposalsData } from './utils/getProposalsData';
import { getVotingData } from './utils/getVotingData';

export type FetchProposalsDataForListParams = Pick<
ContractsConstants,
Expand All @@ -33,165 +21,25 @@ export async function fetchProposalsDataForList({
}: {
input: FetchProposalsDataForListParams;
}) {
const { clients, userAddress, representativeAddress, votingConfigs } = input;

try {
throw new Error('TODO: API not implemented');
} catch (e) {
console.error(
'Error getting proposals data from API, using RPC fallback',
e,
);
const proposalsData = (await getProposalsData(input)).sort(
(a, b) => b.proposal.id - a.proposal.id,
);

const payloadsChainsWithIds: Record<number, number[]> = {};
const initialPayloads = proposalsData
const proposalsData = (await getProposalsData(input))
.sort((a, b) => b.proposal.id - a.proposal.id)
.map((proposal) => {
return proposal.proposal.payloads;
})
.flat();
const payloadsChains = initialPayloads
.map((payload) => payload.chain)
.filter((value, index, self) => self.indexOf(value) === index);
payloadsChains.forEach((chainId) => {
payloadsChainsWithIds[Number(chainId)] = initialPayloads
.filter((payload) => Number(payload.chain) === Number(chainId))
.map((payload) => payload.payloadId)
.filter((value, index, self) => self.indexOf(value) === index);
});
const payloadsData = (
await Promise.all(
Object.entries(payloadsChainsWithIds).map(
async ([chainId, payloadsIds]) =>
await getPayloadsData({
chainId: Number(chainId),
payloadsIds,
}),
),
)
).flat();

const proposalsWithPayloads = proposalsData.map((proposal) => {
const proposalPayloads = proposal.proposal.payloads.map((payload) => {
return payloadsData.filter(
(p) =>
Number(p.payload.id) === Number(payload.payloadId) &&
Number(p.payload.data.chain) === Number(payload.chain) &&
p.payload.data.payloadsController === payload.payloadsController,
)[0];
});
const isProposalPayloadsFinished = proposalPayloads.every(
(payload) =>
payload && payload?.payload.data.state > InitialPayloadState.Queued,
);
return {
proposal: {
...proposal,
isFinished:
proposal.proposal.state === InitialProposalState.Executed
? isProposalPayloadsFinished
: proposal.proposal.state > InitialProposalState.Executed,
},
payloads: proposalPayloads,
};
});

const activeIds = proposalsWithPayloads
.filter((item) => !item.proposal.isFinished)
.map((item) => item.proposal.proposal.id);
const finishedIds = proposalsWithPayloads
.filter((item) => item.proposal.isFinished)
.map((item) => item.proposal.proposal.id);

const proposalsForGetVotingData = await Promise.all(
activeIds.map(async (id) => {
const proposal = proposalsWithPayloads.filter(
(item) => item.proposal.proposal.id === id,
)[0].proposal;
const votingChainId = await readContract(
clients[appConfig.govCoreChainId],
{
abi: IVotingPortal_ABI,
address: proposal.proposal.votingPortal,
functionName: 'VOTING_MACHINE_CHAIN_ID',
args: [],
},
);
return {
id: BigInt(proposal.proposal.id),
votingChainId: Number(votingChainId),
snapshotBlockHash: proposal.proposal.snapshotBlockHash,
...proposal.proposal,
title: proposal.ipfs?.title,
};
}),
);

const votingProposalsData =
proposalsForGetVotingData.length > 0
? await getVotingData({
initialProposals: proposalsForGetVotingData,
userAddress,
representativeAddress,
clients,
})
: [];

const activeProposalsData =
activeIds.length > 0
? await Promise.all(
activeIds.map(async (id) => {
const data = proposalsWithPayloads.filter(
(item) => item.proposal.proposal.id === id,
)[0];
const votingData = votingProposalsData.filter(
(data) => data.proposalData.id === BigInt(id),
)[0];
const votingConfig = votingConfigs.filter(
(config) =>
config.accessLevel === data.proposal.proposal.accessLevel,
)[0];
return formatActiveProposalData({
...input,
...votingConfig,
core: data.proposal.proposal,
payloads: data.payloads.map((payload) => payload.payload),
voting: votingData,
title: data.proposal.ipfs?.title,
});
}),
)
: [];

const finishedProposalsData = finishedIds.map((id) => {
const data = proposalsWithPayloads.filter(
(item) => item.proposal.proposal.id === id,
)[0];
const votingConfig = votingConfigs.filter(
(config) => config.accessLevel === data.proposal.proposal.accessLevel,
)[0];
const { proposalState, finishedTimestamp } =
getStateAndTimestampForFinishedProposal({
...input,
...votingConfig,
core: data.proposal.proposal,
payloads: data.payloads.map((payload) => payload.payload),
});
return {
proposalId: Number(data.proposal.proposal.id),
title:
data.proposal.ipfs?.title ?? `Proposal #${data.proposal.proposal.id}`,
ipfsHash: data.proposal.proposal.ipfsHash,
state: {
state: proposalState,
timestamp: finishedTimestamp,
},
};
});
return await getDataForList({
input,
proposals: proposalsData,
getPayloadsData: ({ ...props }) => getPayloadsData({ ...props }),
});

return {
activeProposalsData,
finishedProposalsData,
};
}
}
Loading

1 comment on commit 2244eb9

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This commit was deployed on ipfs

Please sign in to comment.