Skip to content

Commit

Permalink
/delegates performance optimization (#162)
Browse files Browse the repository at this point in the history
* 🛠️ integrate react cache; cache delegate and wallet address in genMetadata

* 🛠️ drop unused import; do not double-fetch delegate statement; use cached delegate and address in component

* 🛠️ return addresses as-is if already resolved from ENS

* 📈 cache delegate statement; move caching into fetch delegate + resolve ENS
  • Loading branch information
Flip-Liquid committed Mar 12, 2024
1 parent 9e96ba3 commit 7ff67e8
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 27 deletions.
46 changes: 23 additions & 23 deletions src/app/delegates/[addressOrENSName]/page.tsx
Expand Up @@ -2,11 +2,10 @@
* Show page for a single delegate
* Takes in the delegate address as a parameter
*/

import { Metadata, ResolvingMetadata } from 'next'
import DelegateCard from "@/components/Delegates/DelegateCard/DelegateCard";
import DelegateVotes from "@/components/Delegates/DelegateVotes/DelegateVotes";
import { VStack } from "@/components/Layout/Stack";
import { VotesSortOrder } from "@/app/api/common/votes/vote";
import DelegateVotesProvider from "@/contexts/DelegateVotesContext";
import DelegationsContainer from "@/components/Delegates/Delegations/DelegationsContainer";
import ResourceNotFound from "@/components/shared/ResourceNotFound/ResourceNotFound";
Expand All @@ -16,31 +15,30 @@ import {
fetchCurrentDelegatees,
fetchCurrentDelegators,
fetchDelegate,
fetchDelegateStatement,
fetchVotesForDelegate,
} from "@/app/delegates/actions";
import { formatNumber } from "@/lib/tokenUtils";
import {
processAddressOrEnsName,
resolveENSName,
resolveENSProfileImage,
} from "@/app/lib/ENSUtils";

export async function generateMetadata(
{ params }: { params: { addressOrENSName: string } },
parent: any
) {
const [delegate, delegateStatement, address] = await Promise.all([
fetchDelegate(params.addressOrENSName),
fetchDelegateStatement(params.addressOrENSName),
processAddressOrEnsName(params.addressOrENSName),
parent: ResolvingMetadata
): Promise<Metadata> {
// cache ENS address upfront for all subsequent queries
// TODO: change subqueries to use react cache
const address = await resolveENSName(params.addressOrENSName);
const ensOrTruncatedAddress = await processAddressOrEnsName(params.addressOrENSName);
const [delegate, avatar] = await Promise.all([
fetchDelegate(address || params.addressOrENSName),
resolveENSProfileImage(address || params.addressOrENSName),
]);

const avatar = await resolveENSProfileImage(
address || params.addressOrENSName
);

const statement = (
delegateStatement?.payload as { delegateStatement: string }
delegate.statement?.payload as { delegateStatement: string }
)?.delegateStatement;

const imgParams = [
Expand All @@ -54,9 +52,9 @@ export async function generateMetadata(

const preview = `/api/images/og/delegate?${imgParams.join(
"&"
)}&address=${address}`;
const title = `${address} on Agora`;
const description = `See what ${address} believes and how they vote on Optimism governance.`;
)}&address=${ensOrTruncatedAddress}`;
const title = `${ensOrTruncatedAddress} on Agora`;
const description = `See what ${ensOrTruncatedAddress} believes and how they vote on Optimism governance.`;

return {
title: title,
Expand All @@ -78,15 +76,17 @@ export default async function Page({
}: {
params: { addressOrENSName: string };
}) {
const [delegate, delegateVotes, statement, delegates, delegators] =
const address = await resolveENSName(addressOrENSName) || addressOrENSName;
const [delegate, delegateVotes, delegates, delegators] =
await Promise.all([
fetchDelegate(addressOrENSName),
fetchVotesForDelegate(addressOrENSName),
fetchDelegateStatement(addressOrENSName),
fetchCurrentDelegatees(addressOrENSName),
fetchCurrentDelegators(addressOrENSName),
fetchDelegate(address),
fetchVotesForDelegate(address),
fetchCurrentDelegatees(address),
fetchCurrentDelegators(address),
]);

const statement = delegate.statement;

if (!delegate) {
return (
<ResourceNotFound message="Hmm... can't find that address or ENS, please check again." />
Expand Down
9 changes: 7 additions & 2 deletions src/app/delegates/actions.ts
Expand Up @@ -2,6 +2,7 @@

import { getAllForAForAdvancedDelegation } from "@/app/api/delegations/getDelegations";
import { type DelegateStatementFormValues } from "@/components/DelegateStatement/CurrentDelegateStatement";
import { cache } from "react";
import { revalidatePath } from "next/cache";
import { getVotesForDelegate } from "@/app/api/common/votes/getVotes";
import {
Expand Down Expand Up @@ -50,7 +51,9 @@ export async function getProxyAddress(addressOrENSName: string) {
}

export async function fetchDelegate(addressOrENSName: string) {
return getDelegate(addressOrENSName);
return cache(
(address: string) => getDelegate(address)
)(addressOrENSName);
}

export async function submitDelegateStatement({
Expand All @@ -75,7 +78,9 @@ export async function submitDelegateStatement({
}

export async function fetchDelegateStatement(addressOrENSName: string) {
return getDelegateStatement(addressOrENSName);
return cache(
(addressOrENS: string) => getDelegateStatement(addressOrENS)
)(addressOrENSName);
}

export async function fetchVotesForDelegate(
Expand Down
15 changes: 13 additions & 2 deletions src/app/lib/ENSUtils.ts
@@ -1,9 +1,17 @@
import { ethProvider } from "@/app/lib/provider";
import { truncateAddress } from "@/app/lib/utils/text";
import { isAddress } from "viem";
import { cache } from "react";

export async function resolveENSName(nameOrAddress: string) {
if (isAddress(nameOrAddress)) {
return nameOrAddress;
}

const address = await cache(
(name: string) => ethProvider.resolveName(name)
)(nameOrAddress);

export async function resolveENSName(name: string) {
const address = await ethProvider.resolveName(name);
if (!address) {
throw new Error("No address found for ENS name");
}
Expand Down Expand Up @@ -44,6 +52,9 @@ export async function resolveENSProfileImage(
}
}

/*
Returns the ENS name for the address if it exists, otherwise truncates address
*/
export async function processAddressOrEnsName(addressOrENSName: string) {
// Assume resolved ens name
if (!isAddress(addressOrENSName)) {
Expand Down

0 comments on commit 7ff67e8

Please sign in to comment.