diff --git a/app/proposal/page.page.tsx b/app/proposal/page.page.tsx index dc402c15..b7a8354a 100644 --- a/app/proposal/page.page.tsx +++ b/app/proposal/page.page.tsx @@ -2,7 +2,6 @@ import { IGovernanceCore_ABI } from '@bgd-labs/aave-address-book'; import { CachedDetails, getGovCoreConfigs, - getProposalMetadata, getProposalState, getVotingMachineProposalState, ProposalMetadata, @@ -23,6 +22,7 @@ import { cachedVotesPath, githubStartUrl, } from '../../src/utils/cacheGithubLinks'; +import { getProposalMetadata } from '../../src/utils/getProposalMetadata'; import { initialClients } from '../../src/utils/initialClients'; export const revalidate = 0; @@ -44,7 +44,7 @@ export async function generateMetadata({ if (ipfsHash && proposalId) { try { - const ipfsData = await getProposalMetadata(ipfsHash); + const ipfsData = await getProposalMetadata({ hash: ipfsHash }); return { title: `${metaTexts.main}${metaTexts.proposalId(proposalId)}`, @@ -197,7 +197,7 @@ export default async function ProposalPage({ try { ipfsDataSSR = cachedDetailsData?.ipfs ?? - (ipfsHash ? await getProposalMetadata(ipfsHash) : undefined); + (ipfsHash ? await getProposalMetadata({ hash: ipfsHash }) : undefined); } catch (e) { ipfsDataSSR = cachedDetailsData?.ipfs; } diff --git a/package.json b/package.json index 52f88ad5..5e38ba3c 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ }, "dependencies": { "@bgd-labs/aave-address-book": "^2.26.0", - "@bgd-labs/aave-governance-ui-helpers": "^3.1.3", + "@bgd-labs/aave-governance-ui-helpers": "^3.1.5", "@bgd-labs/frontend-web3-utils": "^1.2.1", "@emotion/cache": "^11.11.0", "@emotion/react": "^11.11.4", diff --git a/src/proposals/components/proposalList/ActiveProposalListItem.tsx b/src/proposals/components/proposalList/ActiveProposalListItem.tsx index c38297dc..d5861415 100644 --- a/src/proposals/components/proposalList/ActiveProposalListItem.tsx +++ b/src/proposals/components/proposalList/ActiveProposalListItem.tsx @@ -6,7 +6,7 @@ import { import { WalletType } from '@bgd-labs/frontend-web3-utils'; import { Box, useTheme } from '@mui/system'; import React, { useEffect, useState } from 'react'; -import { Hex, zeroAddress } from 'viem'; +import { zeroAddress } from 'viem'; import { useStore } from '../../../store/ZustandStoreProvider'; import { Link } from '../../../ui'; @@ -44,7 +44,6 @@ export function ActiveProposalListItem({ const appClients = useStore((state) => state.appClients); const ipfsDataErrors = useStore((state) => state.ipfsDataErrors); const ipfsData = useStore((state) => state.ipfsData); - const getIpfsData = useStore((state) => state.getIpfsData); let activeWallet = useStore((state) => state.activeWallet); const proposal = proposalData.proposal; @@ -55,22 +54,13 @@ export function ActiveProposalListItem({ const [isIPFSError, setIsIpfsError] = useState( ipfsDataErrors[proposal.data.ipfsHash] && !ipfsData[proposal.data.ipfsHash], ); - const [ipfsErrorCount, setIpfsErrorCount] = useState(0); - - const MAX_COUNT = 5; useEffect(() => { setIsIpfsError( ipfsDataErrors[proposal.data.ipfsHash] && !ipfsData[proposal.data.ipfsHash], ); - if (isIPFSError && ipfsErrorCount <= MAX_COUNT) { - setTimeout(async () => { - getIpfsData([proposal.data.id], proposal.data.ipfsHash as Hex); - setIpfsErrorCount(ipfsErrorCount + 1); - }, 1000); - } - }, [ipfsErrorCount, isIPFSError, Object.keys(ipfsDataErrors).length]); + }, [isIPFSError, Object.keys(ipfsDataErrors).length]); if (isForHelpModal) { activeWallet = { @@ -214,7 +204,7 @@ export function ActiveProposalListItem({ ? `${theme.palette.$text} !important` : theme.palette.$text, }}> - {isIPFSError && ipfsErrorCount > MAX_COUNT ? ( + {isIPFSError ? ( 'Ipfs getting error' ) : isIPFSError ? ( diff --git a/src/proposals/store/proposalsSlice.ts b/src/proposals/store/proposalsSlice.ts index c5a7434f..b1511191 100644 --- a/src/proposals/store/proposalsSlice.ts +++ b/src/proposals/store/proposalsSlice.ts @@ -4,7 +4,6 @@ import { checkHash, ContractsConstants, getProofOfRepresentative, - getProposalMetadata, getProposalStepsAndAmounts, getVotingMachineProposalState, getVotingProofs, @@ -38,7 +37,7 @@ import { import { IUISlice } from '../../ui/store/uiSlice'; import { texts } from '../../ui/utils/texts'; import { appConfig } from '../../utils/appConfig'; -import { ipfsGateway } from '../../utils/configs'; +import { getProposalMetadata } from '../../utils/getProposalMetadata'; import { PAGE_SIZE } from '../../web3/services/govDataService'; import { ICreationFeesSlice } from '../../web3/store/creationFeesSlice'; import { ENSDataExists } from '../../web3/store/ensSelectors'; @@ -513,12 +512,10 @@ export const createProposalsSlice: StoreSlice< filteredNewIpfsHashes.map(async (hash) => { try { - const ipfsData = await getProposalMetadata( + const ipfsData = await getProposalMetadata({ hash, - ipfsGateway, - get().setIpfsDataErrors, - texts.other.fetchFromIpfsIncorrectHash, - ); + setIpfsError: get().setIpfsDataErrors, + }); if (ipfsData) { get().setIpfsDataErrors(hash, '', true); diff --git a/src/utils/cacheGithubLinks.ts b/src/utils/cacheGithubLinks.ts index 123a6230..08c37363 100644 --- a/src/utils/cacheGithubLinks.ts +++ b/src/utils/cacheGithubLinks.ts @@ -1,6 +1,8 @@ import { coreName } from './appConfig'; -export const githubStartUrl = `https://raw.githubusercontent.com/bgd-labs/aave-governance-ui-helpers/main/cache/ui/${coreName}`; +export const githubInitialUrl = + 'https://raw.githubusercontent.com/bgd-labs/aave-governance-ui-helpers/main/cache'; +export const githubStartUrl = `${githubInitialUrl}/ui/${coreName}`; export const listViewPath = '/list_view_proposals.json'; export const cachedProposalsIdsPath = '/cached_proposals_ids.json'; @@ -15,3 +17,6 @@ export const cachedVotesPath = (id: number) => export const cachedEventsPath = (id: number) => `/events/proposal_${id}_events.json`; + +export const cachedIPFSDataPath = (ipfsHash: string) => + `/ipfs/${ipfsHash}.json`; diff --git a/src/utils/configs.ts b/src/utils/configs.ts index 7ce09cc2..3d30e9bd 100644 --- a/src/utils/configs.ts +++ b/src/utils/configs.ts @@ -4,5 +4,11 @@ import { CHAINS } from './chains'; // ipfs gateway to get proposals metadata export const ipfsGateway = 'https://cloudflare-ipfs.com/ipfs'; +export const fallbackGateways = [ + 'https://ipfs.io', + 'https://ipfs.eth.aragon.network', + 'https://dweb.link', + 'https://ipfs.runfission.com', +]; export const chainInfoHelper = initChainInformationConfig(CHAINS); diff --git a/src/utils/getProposalMetadata.ts b/src/utils/getProposalMetadata.ts new file mode 100644 index 00000000..77c1caa0 --- /dev/null +++ b/src/utils/getProposalMetadata.ts @@ -0,0 +1,53 @@ +import { + getProposalMetadata as baseGetProposalMetadata, + ProposalMetadata, +} from '@bgd-labs/aave-governance-ui-helpers'; +import matter from 'gray-matter'; + +import { texts } from '../ui/utils/texts'; +import { cachedIPFSDataPath, githubStartUrl } from './cacheGithubLinks'; +import { fallbackGateways, ipfsGateway } from './configs'; + +export async function getProposalMetadata({ + hash, + setIpfsError, +}: { + hash: string; + setIpfsError?: (ipfsHash: string, text?: string, remove?: boolean) => void; +}): Promise { + try { + const request = await fetch(`${githubStartUrl}${cachedIPFSDataPath(hash)}`); + if (request.ok) { + const response = await request.json(); + const { content, data } = matter(response.description); + return { + ...response, + ipfsHash: hash, + description: content, + ...data, + }; + } else { + console.error( + "Can't fetch cached ipfs data. Try to fetch from IPFS gateway", + ); + return await baseGetProposalMetadata({ + hash, + gateway: ipfsGateway, + setIpfsError, + errorText: texts.other.fetchFromIpfsError, + fallbackGateways, + }); + } + } catch (e) { + console.error( + 'An error occurred while fetching proposal metadata from IPFS, trying to request one more time.', + ); + return await baseGetProposalMetadata({ + hash, + gateway: ipfsGateway, + setIpfsError, + errorText: texts.other.fetchFromIpfsError, + fallbackGateways, + }); + } +} diff --git a/yarn.lock b/yarn.lock index 4015d154..fbeed352 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1383,10 +1383,10 @@ resolved "https://registry.yarnpkg.com/@bgd-labs/aave-address-book/-/aave-address-book-2.26.0.tgz#d861386eb1fbc977a82c7f1c1ce4c1e6c30e77d0" integrity sha512-1VjBruXMHEpPr7X6/m9XZH0fIxfNr2FgEvzhzCLb7Fb5opYU+4yTr7C+ATmQGGoy2I4PYDMr0kH6TMg3EpfvTw== -"@bgd-labs/aave-governance-ui-helpers@^3.1.3": - version "3.1.3" - resolved "https://registry.yarnpkg.com/@bgd-labs/aave-governance-ui-helpers/-/aave-governance-ui-helpers-3.1.3.tgz#aada6c1e043ca3e12097bcdd7d59ec1e396f6519" - integrity sha512-RiO46hwoz13309RqqQXKrxy/U+Ybb8DBYckKbZwiV7gXhbmBf2Hz6TRU78JsGPOMz0UUA7CRrb6V1c1OS48wqw== +"@bgd-labs/aave-governance-ui-helpers@^3.1.5": + version "3.1.5" + resolved "https://registry.yarnpkg.com/@bgd-labs/aave-governance-ui-helpers/-/aave-governance-ui-helpers-3.1.5.tgz#028bd728c379d567201a97c57ade28f197ef90c1" + integrity sha512-OX7kbA6+V6ot/XA3ue1HFnxyhRT8v2Yllah4njXr7VH+PxeAIs1i5cbK2cN6qJ6tPHAC/JGFkGaSHIxdkjB3TQ== dependencies: bs58 "^5.0.0" dayjs "^1.11.10"