Skip to content

Commit 37b3d7f

Browse files
Add activity log section to transaction page (#7529)
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
1 parent 8def4f3 commit 37b3d7f

File tree

19 files changed

+532
-84
lines changed

19 files changed

+532
-84
lines changed

apps/dashboard/src/@/components/contract-components/shared/contract-id-image.tsx

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
import type { StaticImageData } from "next/image";
44
import Image from "next/image";
55
import type { FetchDeployMetadataResult } from "thirdweb/contract";
6-
import { serverThirdwebClient } from "@/constants/thirdweb-client.server";
6+
import { DASHBOARD_THIRDWEB_SECRET_KEY } from "@/constants/server-envs";
7+
import { getConfiguredThirdwebClient } from "@/constants/thirdweb.server";
78
import { replaceIpfsUrl } from "@/lib/sdk";
89
import generalContractIcon from "../../../../../public/assets/tw-icons/general.png";
910

@@ -26,7 +27,17 @@ export const ContractIdImage: React.FC<ContractIdImageProps> = ({
2627
<img
2728
alt=""
2829
className="size-8 rounded-full"
29-
src={replaceIpfsUrl(logo, serverThirdwebClient)}
30+
src={
31+
DASHBOARD_THIRDWEB_SECRET_KEY
32+
? replaceIpfsUrl(
33+
logo,
34+
getConfiguredThirdwebClient({
35+
secretKey: DASHBOARD_THIRDWEB_SECRET_KEY,
36+
teamId: undefined,
37+
}),
38+
)
39+
: logo
40+
}
3041
/>
3142
);
3243
}

apps/dashboard/src/@/constants/thirdweb-client.server.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ import "server-only";
33
import { DASHBOARD_THIRDWEB_SECRET_KEY } from "./server-envs";
44
import { getConfiguredThirdwebClient } from "./thirdweb.server";
55

6+
// During build time, the secret key might not be available
7+
// Create a client that will work for build but may fail at runtime if secret key is needed
68
export const serverThirdwebClient = getConfiguredThirdwebClient({
7-
secretKey: DASHBOARD_THIRDWEB_SECRET_KEY,
9+
secretKey: DASHBOARD_THIRDWEB_SECRET_KEY || "dummy-build-time-secret",
810
teamId: undefined,
911
});

apps/dashboard/src/@/constants/thirdweb.server.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,18 @@ export function getConfiguredThirdwebClient(options: {
7676
});
7777
}
7878

79+
// During build time, provide fallbacks if credentials are missing
80+
const clientId = NEXT_PUBLIC_DASHBOARD_CLIENT_ID || "dummy-build-client";
81+
const secretKey = options.secretKey || undefined;
82+
7983
return createThirdwebClient({
80-
clientId: NEXT_PUBLIC_DASHBOARD_CLIENT_ID,
84+
clientId: clientId,
8185
config: {
8286
storage: {
8387
gatewayUrl: NEXT_PUBLIC_IPFS_GATEWAY_URL,
8488
},
8589
},
86-
secretKey: options.secretKey,
90+
secretKey: secretKey,
8791
teamId: options.teamId,
8892
});
8993
}

apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/opengraph-image.tsx

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { ImageResponse } from "next/og";
22
import { useId } from "react";
33
import { download } from "thirdweb/storage";
4-
import { serverThirdwebClient } from "@/constants/thirdweb-client.server";
4+
import { DASHBOARD_THIRDWEB_SECRET_KEY } from "@/constants/server-envs";
5+
import { getConfiguredThirdwebClient } from "@/constants/thirdweb.server";
56
import { fetchChain } from "@/utils/fetchChain";
67

78
// Route segment config
@@ -81,16 +82,29 @@ export default async function Image({
8182
fetch(new URL("og-lib/fonts/inter/700.ttf", import.meta.url)).then((res) =>
8283
res.arrayBuffer(),
8384
),
84-
// download the chain icon if there is one
85-
chain.icon?.url && hasWorkingChainIcon
86-
? download({
87-
client: serverThirdwebClient,
88-
uri: chain.icon.url,
89-
}).then((res) => res.arrayBuffer())
85+
// download the chain icon if there is one and secret key is available
86+
chain.icon?.url && hasWorkingChainIcon && DASHBOARD_THIRDWEB_SECRET_KEY
87+
? (async () => {
88+
try {
89+
const client = getConfiguredThirdwebClient({
90+
secretKey: DASHBOARD_THIRDWEB_SECRET_KEY,
91+
teamId: undefined,
92+
});
93+
const response = await download({
94+
client,
95+
uri: chain.icon?.url || "",
96+
});
97+
return response.arrayBuffer();
98+
} catch (error) {
99+
// If download fails, return undefined to fallback to no icon
100+
console.warn("Failed to download chain icon:", error);
101+
return undefined;
102+
}
103+
})()
90104
: undefined,
91105
// download the background image (based on chain)
92106
fetch(
93-
chain.icon?.url && hasWorkingChainIcon
107+
chain.icon?.url && hasWorkingChainIcon && DASHBOARD_THIRDWEB_SECRET_KEY
94108
? new URL(
95109
"og-lib/assets/chain/bg-with-icon.png",
96110

@@ -118,7 +132,7 @@ export default async function Image({
118132
/>
119133
{/* the actual component starts here */}
120134

121-
{hasWorkingChainIcon && (
135+
{hasWorkingChainIcon && chainIcon && (
122136
<img
123137
alt=""
124138
// @ts-expect-error - TS doesn't know about the ImageResponse component

apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/getContractFromParams.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { getAddress, getContract, isAddress } from "thirdweb";
22
import { localhost } from "thirdweb/chains";
3-
import { serverThirdwebClient } from "@/constants/thirdweb-client.server";
3+
import { DASHBOARD_THIRDWEB_SECRET_KEY } from "@/constants/server-envs";
4+
import { getConfiguredThirdwebClient } from "@/constants/thirdweb.server";
45
import { mapV4ChainToV5Chain } from "@/utils/map-chains";
56
import { getUserThirdwebClient } from "../../../../../../../@/api/auth-token";
67
import { fetchChainWithLocalOverrides } from "../../../../../../../@/utils/fetchChainWithLocalOverrides";
@@ -18,13 +19,21 @@ export async function getContractPageParamsInfo(params: {
1819
return undefined;
1920
}
2021

21-
// attempt to get the auth token
22+
// Create server client only if secret key is available
23+
if (!DASHBOARD_THIRDWEB_SECRET_KEY) {
24+
return undefined;
25+
}
26+
27+
const serverClient = getConfiguredThirdwebClient({
28+
secretKey: DASHBOARD_THIRDWEB_SECRET_KEY,
29+
teamId: undefined,
30+
});
2231

2332
const serverContract = getContract({
2433
address: contractAddress,
2534
// eslint-disable-next-line no-restricted-syntax
2635
chain: mapV4ChainToV5Chain(chainMetadata),
27-
client: serverThirdwebClient,
36+
client: serverClient,
2837
});
2938

3039
const clientContract = getContract({

apps/dashboard/src/app/(app)/(dashboard)/(chain)/components/server/chain-icon.tsx

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* eslint-disable @next/next/no-img-element */
22
import "server-only";
33
import { DASHBOARD_THIRDWEB_SECRET_KEY } from "@/constants/server-envs";
4-
import { serverThirdwebClient } from "@/constants/thirdweb-client.server";
4+
import { getConfiguredThirdwebClient } from "@/constants/thirdweb.server";
55
import { cn } from "@/lib/utils";
66
import { resolveSchemeWithErrorHandler } from "@/utils/resolveSchemeWithErrorHandler";
77
import { fallbackChainIcon } from "../../../../../../@/utils/chain-icons";
@@ -13,10 +13,16 @@ export async function ChainIcon(props: {
1313
if (props.iconUrl) {
1414
let imageLink = fallbackChainIcon;
1515

16-
const resolved = resolveSchemeWithErrorHandler({
17-
client: serverThirdwebClient,
18-
uri: props.iconUrl,
19-
});
16+
// Only resolve if we have a secret key available
17+
const resolved = DASHBOARD_THIRDWEB_SECRET_KEY
18+
? resolveSchemeWithErrorHandler({
19+
client: getConfiguredThirdwebClient({
20+
secretKey: DASHBOARD_THIRDWEB_SECRET_KEY,
21+
teamId: undefined,
22+
}),
23+
uri: props.iconUrl,
24+
})
25+
: null;
2026

2127
if (resolved) {
2228
// check if it loads or not

apps/dashboard/src/app/(app)/(dashboard)/profile/[addressOrEns]/opengraph-image.tsx

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ import { notFound } from "next/navigation";
22
import { ImageResponse } from "next/og";
33
import { resolveAvatar } from "thirdweb/extensions/ens";
44
import { GradientBlobbie } from "@/components/blocks/avatar/GradientBlobbie";
5-
import { serverThirdwebClient } from "@/constants/thirdweb-client.server";
5+
import { DASHBOARD_THIRDWEB_SECRET_KEY } from "@/constants/server-envs";
6+
import { getConfiguredThirdwebClient } from "@/constants/thirdweb.server";
67
/* eslint-disable @next/next/no-img-element */
78
import { resolveSchemeWithErrorHandler } from "@/utils/resolveSchemeWithErrorHandler";
89
import { shortenIfAddress } from "@/utils/usedapp-external";
@@ -23,10 +24,18 @@ type PageProps = {
2324

2425
export default async function Image(props: PageProps) {
2526
const params = await props.params;
26-
const resolvedInfo = await resolveAddressAndEns(
27-
params.addressOrEns,
28-
serverThirdwebClient,
29-
);
27+
28+
// Create client only if secret key is available
29+
if (!DASHBOARD_THIRDWEB_SECRET_KEY) {
30+
notFound();
31+
}
32+
33+
const client = getConfiguredThirdwebClient({
34+
secretKey: DASHBOARD_THIRDWEB_SECRET_KEY,
35+
teamId: undefined,
36+
});
37+
38+
const resolvedInfo = await resolveAddressAndEns(params.addressOrEns, client);
3039

3140
if (!resolvedInfo) {
3241
notFound();
@@ -43,14 +52,14 @@ export default async function Image(props: PageProps) {
4352

4453
const ensImage = resolvedInfo.ensName
4554
? await resolveAvatar({
46-
client: serverThirdwebClient,
55+
client,
4756
name: resolvedInfo.ensName,
4857
})
4958
: null;
5059

5160
const resolvedENSImageSrc = ensImage
5261
? resolveSchemeWithErrorHandler({
53-
client: serverThirdwebClient,
62+
client,
5463
uri: ensImage,
5564
})
5665
: null;

apps/dashboard/src/app/(app)/(dashboard)/published-contract/[publisher]/[contract_id]/[version]/opengraph-image.tsx

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { format } from "date-fns";
22
import { getSocialProfiles } from "thirdweb/social";
3-
import { serverThirdwebClient } from "@/constants/thirdweb-client.server";
3+
import { DASHBOARD_THIRDWEB_SECRET_KEY } from "@/constants/server-envs";
4+
import { getConfiguredThirdwebClient } from "@/constants/thirdweb.server";
45
import { resolveEns } from "@/lib/ens";
56
import { correctAndUniqueLicenses } from "@/lib/licenses";
67
import { getPublishedContractsWithPublisherMapping } from "../utils/getPublishedContractsWithPublisherMapping";
@@ -22,17 +23,25 @@ export default async function Image(props: {
2223
}) {
2324
const { publisher, contract_id } = props.params;
2425

26+
// Create client only if secret key is available
27+
if (!DASHBOARD_THIRDWEB_SECRET_KEY) {
28+
return null;
29+
}
30+
31+
const client = getConfiguredThirdwebClient({
32+
secretKey: DASHBOARD_THIRDWEB_SECRET_KEY,
33+
teamId: undefined,
34+
});
35+
2536
const [publishedContracts, socialProfiles] = await Promise.all([
2637
getPublishedContractsWithPublisherMapping({
27-
client: serverThirdwebClient,
38+
client,
2839
contract_id: contract_id,
2940
publisher: publisher,
3041
}),
3142
getSocialProfiles({
32-
address:
33-
(await resolveEns(publisher, serverThirdwebClient)).address ||
34-
publisher,
35-
client: serverThirdwebClient,
43+
address: (await resolveEns(publisher, client)).address || publisher,
44+
client,
3645
}),
3746
]);
3847

apps/dashboard/src/app/(app)/(dashboard)/published-contract/[publisher]/[contract_id]/opengraph-image.tsx

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { format } from "date-fns";
22
import { getSocialProfiles } from "thirdweb/social";
3-
import { serverThirdwebClient } from "@/constants/thirdweb-client.server";
3+
import { DASHBOARD_THIRDWEB_SECRET_KEY } from "@/constants/server-envs";
4+
import { getConfiguredThirdwebClient } from "@/constants/thirdweb.server";
45
import { resolveEns } from "@/lib/ens";
56
import { correctAndUniqueLicenses } from "@/lib/licenses";
67
import { getLatestPublishedContractsWithPublisherMapping } from "./utils/getPublishedContractsWithPublisherMapping";
@@ -21,17 +22,25 @@ export default async function Image(props: {
2122
}) {
2223
const { publisher, contract_id } = props.params;
2324

25+
// Create client only if secret key is available
26+
if (!DASHBOARD_THIRDWEB_SECRET_KEY) {
27+
return null;
28+
}
29+
30+
const client = getConfiguredThirdwebClient({
31+
secretKey: DASHBOARD_THIRDWEB_SECRET_KEY,
32+
teamId: undefined,
33+
});
34+
2435
const [publishedContract, socialProfiles] = await Promise.all([
2536
getLatestPublishedContractsWithPublisherMapping({
26-
client: serverThirdwebClient,
37+
client,
2738
contract_id: contract_id,
2839
publisher: publisher,
2940
}),
3041
getSocialProfiles({
31-
address:
32-
(await resolveEns(publisher, serverThirdwebClient)).address ||
33-
publisher,
34-
client: serverThirdwebClient,
42+
address: (await resolveEns(publisher, client)).address || publisher,
43+
client,
3544
}),
3645
]);
3746

apps/dashboard/src/app/(app)/(dashboard)/published-contract/[publisher]/[contract_id]/utils/publishedContractOGImageTemplate.tsx

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ import { ImageResponse } from "next/og";
44
import { isAddress } from "thirdweb";
55
import { download } from "thirdweb/storage";
66
import { shortenAddress } from "thirdweb/utils";
7-
import { serverThirdwebClient } from "@/constants/thirdweb-client.server";
7+
import { DASHBOARD_THIRDWEB_SECRET_KEY } from "@/constants/server-envs";
8+
import { getConfiguredThirdwebClient } from "@/constants/thirdweb.server";
89

910
const OgBrandIcon: React.FC = () => (
1011
// biome-ignore lint/a11y/noSvgWithoutTitle: not needed
@@ -187,17 +188,41 @@ export async function publishedContractOGImageTemplate(params: {
187188
ibmPlexMono500_,
188189
ibmPlexMono700_,
189190
image,
190-
params.logo
191-
? download({
192-
client: serverThirdwebClient,
193-
uri: params.logo,
194-
}).then((res) => res.arrayBuffer())
191+
params.logo && DASHBOARD_THIRDWEB_SECRET_KEY
192+
? (async () => {
193+
try {
194+
const client = getConfiguredThirdwebClient({
195+
secretKey: DASHBOARD_THIRDWEB_SECRET_KEY,
196+
teamId: undefined,
197+
});
198+
const response = await download({
199+
client,
200+
uri: params.logo || "",
201+
});
202+
return response.arrayBuffer();
203+
} catch (error) {
204+
console.warn("Failed to download logo:", error);
205+
return undefined;
206+
}
207+
})()
195208
: undefined,
196-
params.publisherAvatar
197-
? download({
198-
client: serverThirdwebClient,
199-
uri: params.publisherAvatar,
200-
}).then((res) => res.arrayBuffer())
209+
params.publisherAvatar && DASHBOARD_THIRDWEB_SECRET_KEY
210+
? (async () => {
211+
try {
212+
const client = getConfiguredThirdwebClient({
213+
secretKey: DASHBOARD_THIRDWEB_SECRET_KEY,
214+
teamId: undefined,
215+
});
216+
const response = await download({
217+
client,
218+
uri: params.publisherAvatar || "",
219+
});
220+
return response.arrayBuffer();
221+
} catch (error) {
222+
console.warn("Failed to download avatar:", error);
223+
return undefined;
224+
}
225+
})()
201226
: undefined,
202227
]);
203228

0 commit comments

Comments
 (0)