From ac8b09f35e3f813a0136ba9b6165466c0e782c7b Mon Sep 17 00:00:00 2001 From: MananTank Date: Fri, 18 Apr 2025 22:30:56 +0000 Subject: [PATCH] Dashboard: Add team id to thirdweb client (#6775) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ## PR-Codex overview This PR focuses on updating the usage of the `getThirdwebClient` function throughout the codebase, transitioning to using an options object that includes `jwt` and `teamId`. This change enhances client initialization consistency and improves the handling of team-related functionality. ### Detailed summary - Updated `getThirdwebClient` to accept an options object with `jwt` and `teamId`. - Modified several components to pass the new client structure. - Added constants for `LAST_USED_PROJECT_ID` and `LAST_USED_TEAM_ID`. - Enhanced various components to include `client` as a prop, improving flexibility. - Adjusted several pages and components to handle team IDs better. - Improved cookie management for storing and retrieving the last used team ID. - Updated storybook examples to utilize the new client structure. > The following files were skipped due to too many changes: `apps/dashboard/src/app/team/[team_slug]/(team)/~/usage/overview/components/SponsoredTransactionsTableUI.stories.tsx`, `apps/dashboard/src/app/(dashboard)/profile/[addressOrEns]/components/published-contracts.tsx`, `apps/dashboard/src/app/team/[team_slug]/[project_slug]/components/Transactions/index.tsx`, `apps/dashboard/src/components/configure-networks/ConfigureNetworkForm.tsx`, `apps/dashboard/src/components/contract-components/contract-table/index.tsx`, `apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx`, `apps/dashboard/src/app/(dashboard)/(bridge)/routes/components/server/routelist-card.tsx`, `apps/dashboard/src/app/(dashboard)/(bridge)/routes/components/server/routes-table.tsx`, `apps/dashboard/src/app/(dashboard)/profile/[addressOrEns]/page.tsx`, `apps/dashboard/src/app/(dashboard)/profile/[addressOrEns]/resolveAddressAndEns.tsx`, `apps/dashboard/src/app/team/components/TeamHeader/TeamSelectorMobileMenuButton.tsx`, `apps/dashboard/src/app/team/components/TeamHeader/TeamHeaderUI.stories.tsx`, `apps/dashboard/src/app/(dashboard)/contracts/deploy/[compiler_uri]/page.tsx`, `apps/dashboard/src/app/(dashboard)/(bridge)/routes/components/server/routelist-row.tsx`, `apps/dashboard/src/components/contract-components/contract-deploy-form/custom-contract.tsx`, `apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/members/TeamMembersSettingsPage.stories.tsx`, `apps/dashboard/src/app/(dashboard)/published-contract/[publisher]/[contract_id]/page.tsx`, `apps/dashboard/src/components/contract-components/contract-publish-form/index.tsx`, `apps/dashboard/src/app/nebula-app/(app)/components/ExecuteTransactionCard.stories.tsx`, `apps/dashboard/src/lib/wallet/nfts/alchemy.ts`, `apps/dashboard/src/lib/wallet/nfts/moralis.ts`, `apps/dashboard/src/app/(dashboard)/contracts/publish/[publish_uri]/page.tsx`, `apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/metadata-header.tsx`, `apps/dashboard/src/app/team/components/TeamHeader/team-header-logged-in.client.tsx`, `apps/dashboard/src/components/contract-components/fetchPublishedContracts.ts`, `apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/getModuleInstalledParams.ts`, `apps/dashboard/src/app/nebula-app/(app)/components/Chats.stories.tsx`, `apps/dashboard/src/components/explore/contract-card/index.tsx`, `apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx`, `apps/dashboard/src/app/(dashboard)/(chain)/chainlist/components/server/chainlist-row.tsx`, `apps/dashboard/src/app/(dashboard)/profile/[addressOrEns]/components/PublishedContractTable.tsx`, `apps/dashboard/src/app/(dashboard)/(chain)/chainlist/components/server/chainlist-card.tsx`, `apps/dashboard/src/app/(dashboard)/profile/[addressOrEns]/ProfileUI.tsx`, `apps/dashboard/src/components/contract-components/fetch-contracts-with-versions.ts`, `apps/dashboard/src/app/team/[team_slug]/(team)/layout.tsx`, `apps/dashboard/src/@/components/blocks/Avatars/ProjectAvatar.stories.tsx`, `apps/dashboard/src/app/(dashboard)/published-contract/components/publish-based-deploy.tsx`, `apps/dashboard/src/app/team/components/TeamHeader/team-header.tsx`, `apps/dashboard/src/app/team/[team_slug]/[project_slug]/components/Transactions/TransactionCharts.tsx`, `apps/dashboard/src/app/team/[team_slug]/[project_slug]/layout.tsx`, `apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/cross-chain/data-table.tsx`, `apps/dashboard/src/app/(dashboard)/published-contract/[publisher]/[contract_id]/utils/getPublishedContractsWithPublisherMapping.ts`, `apps/dashboard/src/app/(dashboard)/published-contract/[publisher]/[contract_id]/[version]/page.tsx`, `apps/dashboard/src/@/components/blocks/Avatars/GradientAvatar.stories.tsx`, `apps/dashboard/src/app/team/[team_slug]/[project_slug]/page.tsx`, `apps/dashboard/src/components/contract-components/hooks.ts` > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` --- .../src/@/actions/getBalancesFromMoralis.ts | 6 +-- apps/dashboard/src/@/actions/getWalletNFTs.ts | 4 +- .../blocks/Avatars/GradientAvatar.stories.tsx | 26 ++++++------ .../blocks/Avatars/ProjectAvatar.stories.tsx | 28 +++++++++---- .../src/@/constants/thirdweb.client.ts | 12 +++++- .../src/@/constants/thirdweb.server.ts | 12 +++++- .../client/UniversalBridgeEmbed.tsx | 10 +++-- .../app/(dashboard)/(bridge)/bridge/page.tsx | 7 +++- .../components/server/routelist-card.tsx | 8 ++-- .../components/server/routelist-row.tsx | 8 ++-- .../routes/components/server/routes-table.tsx | 4 ++ .../components/server/BuyFundsSection.tsx | 7 +++- .../components/server/FaucetSection.tsx | 5 ++- .../components/server/chain-header.tsx | 3 ++ .../(chain)/[chain_id]/(chainPage)/layout.tsx | 8 +++- .../(chainPage)/opengraph-image.tsx | 7 ++-- .../(chain)/[chain_id]/(chainPage)/page.tsx | 6 ++- .../(marketplace)/components/list-button.tsx | 4 +- .../(marketplace)/components/list-form.tsx | 4 +- .../_layout/contract-metadata.tsx | 4 +- .../_layout/metadata-header.tsx | 6 ++- .../_utils/getContractFromParams.ts | 8 +++- .../cross-chain/data-table.tsx | 10 ++--- .../[chain_id]/[contractAddress]/layout.tsx | 4 +- .../components/batchMetadata.stories.tsx | 5 +-- .../modules/components/claimable.stories.tsx | 4 +- .../components/getModuleInstalledParams.ts | 12 ++++-- .../components/install-module-params.tsx | 4 +- .../modules/components/mintable.stories.tsx | 5 +-- .../openEditionMetadata.stories.tsx | 5 +-- .../modules/components/royalty.stories.tsx | 5 +-- .../components/transferable.stories.tsx | 5 +-- .../overview/components/published-by-ui.tsx | 4 +- .../components/published-by.server.tsx | 5 +-- .../(chain)/[chain_id]/tx/[txHash]/page.tsx | 5 +-- .../(chain)/chainlist/[chain_type]/page.tsx | 8 +++- .../components/server/chain-table.tsx | 4 ++ .../components/server/chainlist-card.tsx | 8 ++-- .../components/server/chainlist-row.tsx | 8 ++-- .../(dashboard)/(chain)/chainlist/page.tsx | 8 +++- .../(chain)/components/server/chain-icon.tsx | 5 ++- .../contracts/deploy/[compiler_uri]/page.tsx | 7 +++- .../app/(dashboard)/contracts/deploy/page.tsx | 8 +++- .../contracts/publish/[publish_uri]/page.tsx | 6 ++- .../(dashboard)/contracts/publish/page.tsx | 8 +++- .../(dashboard)/explore/[category]/page.tsx | 3 ++ .../src/app/(dashboard)/explore/page.tsx | 5 ++- .../profile/[addressOrEns]/ProfileUI.tsx | 14 +++++-- .../components/PublishedContractTable.tsx | 8 ++-- .../components/published-contracts.tsx | 4 ++ .../[addressOrEns]/opengraph-image.tsx | 4 +- .../profile/[addressOrEns]/page.tsx | 8 +++- .../[addressOrEns]/resolveAddressAndEns.tsx | 7 ++-- .../[contract_id]/[version]/deploy/page.tsx | 8 +++- .../[version]/opengraph-image.tsx | 5 ++- .../[contract_id]/[version]/page.tsx | 8 ++-- .../[publisher]/[contract_id]/deploy/page.tsx | 7 +++- .../[publisher]/[contract_id]/layout.tsx | 2 + .../[contract_id]/opengraph-image.tsx | 5 ++- .../[publisher]/[contract_id]/page.tsx | 4 ++ ...tPublishedContractsWithPublisherMapping.ts | 20 ++++++---- .../publishedContractOGImageTemplate.tsx | 2 +- .../components/contract-header.tsx | 3 ++ .../components/contract-info.tsx | 5 ++- .../components/publish-based-deploy.tsx | 10 ++--- .../(dashboard)/published-contract/page.tsx | 6 ++- .../components/AccountHeaderUI.stories.tsx | 10 +++-- .../account/components/AccountHeaderUI.tsx | 1 + .../contracts/DeployedContractsPageHeader.tsx | 1 - .../overview/AccountTeamsUI.stories.tsx | 11 +++-- apps/dashboard/src/app/account/page.tsx | 10 +++-- .../AccountSettingsPageUI.stories.tsx | 10 ++--- .../src/app/account/settings/page.tsx | 7 +++- .../dashboard/src/app/api/lib/getAuthToken.ts | 13 ++++++ .../src/app/drops/[slug]/opengraph-image.tsx | 7 ++-- apps/dashboard/src/app/drops/[slug]/page.tsx | 2 +- .../get-started/team/[team_slug]/layout.tsx | 7 ++++ .../app/get-started/team/[team_slug]/page.tsx | 7 +++- .../(app)/components/Chats.stories.tsx | 14 ++++--- .../ExecuteTransactionCard.stories.tsx | 12 +++--- .../FloatingChat/FloatingChat.stories.tsx | 8 ++-- .../src/app/project-showcase/[slug]/page.tsx | 2 +- .../src/app/project-showcase/page.tsx | 4 +- .../app/team/[team_slug]/(team)/layout.tsx | 17 ++++++-- .../src/app/team/[team_slug]/(team)/page.tsx | 7 +++- .../ecosystem/create/EcosystemCreatePage.tsx | 10 ++++- .../create/actions/create-ecosystem.ts | 8 +++- .../client/create-ecosystem-form.client.tsx | 6 ++- .../(team)/~/ecosystem/create/page.tsx | 10 ++++- .../general/GeneralSettingsPage.stories.tsx | 4 +- .../~/settings/general/Sidebar.stories.tsx | 8 ++-- .../members/ManageInvitesSection.stories.tsx | 10 +++-- .../TeamMembersSettingsPage.stories.tsx | 12 +++--- .../(team)/~/settings/members/page.tsx | 7 +++- .../[team_slug]/(team)/~/settings/page.tsx | 7 +++- .../SponsoredTransactionsTableUI.stories.tsx | 6 +-- .../team/[team_slug]/(team)/~/usage/page.tsx | 5 ++- .../components/SaveLastUsedProject.ts | 12 +++--- .../Transactions/TransactionCharts.tsx | 12 +++--- .../components/Transactions/index.tsx | 4 ++ .../account-abstraction/factories/page.tsx | 5 ++- .../connect/account-abstraction/page.tsx | 7 +++- .../[team_slug]/[project_slug]/layout.tsx | 16 ++++++-- .../team/[team_slug]/[project_slug]/page.tsx | 26 ++++++++++-- .../ProjectGeneralSettingsPage.stories.tsx | 4 +- .../[project_slug]/settings/page.tsx | 7 +++- .../src/app/team/[team_slug]/layout.tsx | 2 +- .../TeamHeader/TeamHeaderUI.stories.tsx | 11 ++--- .../components/TeamHeader/TeamHeaderUI.tsx | 1 + .../TeamSelectorMobileMenuButton.tsx | 7 ++-- .../team-header-logged-in.client.tsx | 5 ++- .../components/TeamHeader/team-header.tsx | 27 +++++++++++-- .../last-visited-page/SaveLastVisitedPage.tsx | 8 +++- .../buttons/TransactionButton.stories.tsx | 5 +-- .../ConfigureNetworkForm.tsx | 8 +++- .../add-to-project-card.stories.tsx | 8 ++-- .../contract-deploy-form/custom-contract.tsx | 9 +++-- .../contract-publish-form/index.tsx | 4 +- .../landing-fieldset.tsx | 4 +- .../contract-table/index.tsx | 11 +++-- .../fetch-contracts-with-versions.ts | 9 +++-- .../fetchDeployMetadata.ts | 9 +++-- .../fetchPublishedContracts.ts | 14 ++++--- .../fetchPublishedContractsFromDeploy.ts | 4 +- .../components/contract-components/hooks.ts | 40 ++++++++++++------- .../published-contract/index.tsx | 5 ++- .../shared/contract-id-image.tsx | 9 ++++- .../interactive-abi-function.tsx | 5 ++- .../explore/contract-card/index.tsx | 6 ++- .../components/explore/contract-row/index.tsx | 5 ++- .../src/components/icons/ChainIcon.tsx | 4 +- apps/dashboard/src/constants/cookies.ts | 2 + apps/dashboard/src/constants/schemas.ts | 7 +++- .../src/core-ui/batch-upload/batch-table.tsx | 7 +++- apps/dashboard/src/lib/ens.ts | 8 ++-- apps/dashboard/src/lib/rpc.ts | 5 ++- apps/dashboard/src/lib/sdk.ts | 6 +-- apps/dashboard/src/lib/wallet/nfts/alchemy.ts | 15 +++---- .../src/lib/wallet/nfts/isAlchemySupported.ts | 10 +++++ .../src/lib/wallet/nfts/isMoralisSupported.ts | 10 +++++ apps/dashboard/src/lib/wallet/nfts/moralis.ts | 21 ++++------ apps/dashboard/src/stories/utils.tsx | 6 +++ 142 files changed, 768 insertions(+), 353 deletions(-) create mode 100644 apps/dashboard/src/constants/cookies.ts create mode 100644 apps/dashboard/src/lib/wallet/nfts/isAlchemySupported.ts create mode 100644 apps/dashboard/src/lib/wallet/nfts/isMoralisSupported.ts diff --git a/apps/dashboard/src/@/actions/getBalancesFromMoralis.ts b/apps/dashboard/src/@/actions/getBalancesFromMoralis.ts index 9c82d9e850a..a7dc98f04fb 100644 --- a/apps/dashboard/src/@/actions/getBalancesFromMoralis.ts +++ b/apps/dashboard/src/@/actions/getBalancesFromMoralis.ts @@ -1,9 +1,8 @@ "use server"; - -import { getThirdwebClient } from "@/constants/thirdweb.server"; import { defineDashboardChain } from "lib/defineDashboardChain"; import { ZERO_ADDRESS, isAddress, toTokens } from "thirdweb"; import { getWalletBalance } from "thirdweb/wallets"; +import { getUserThirdwebClient } from "../../app/api/lib/getAuthToken"; type BalanceQueryResponse = Array<{ balance: string; @@ -24,6 +23,7 @@ export async function getTokenBalancesFromMoralis(params: { error: string; } > { + const client = await getUserThirdwebClient(); const { contractAddress, chainId } = params; if (!isAddress(contractAddress)) { @@ -39,7 +39,7 @@ export async function getTokenBalancesFromMoralis(params: { const balance = await getWalletBalance({ address: contractAddress, chain, - client: getThirdwebClient(), + client, }); return [ { diff --git a/apps/dashboard/src/@/actions/getWalletNFTs.ts b/apps/dashboard/src/@/actions/getWalletNFTs.ts index 93e78575804..84f99007ab4 100644 --- a/apps/dashboard/src/@/actions/getWalletNFTs.ts +++ b/apps/dashboard/src/@/actions/getWalletNFTs.ts @@ -2,16 +2,16 @@ import { generateAlchemyUrl, - isAlchemySupported, transformAlchemyResponseToNFT, } from "lib/wallet/nfts/alchemy"; import { generateMoralisUrl, - isMoralisSupported, transformMoralisResponseToNFT, } from "lib/wallet/nfts/moralis"; import type { WalletNFT } from "lib/wallet/nfts/types"; import { getVercelEnv } from "../../lib/vercel-utils"; +import { isAlchemySupported } from "../../lib/wallet/nfts/isAlchemySupported"; +import { isMoralisSupported } from "../../lib/wallet/nfts/isMoralisSupported"; import { DASHBOARD_THIRDWEB_CLIENT_ID } from "../constants/env"; type WalletNFTApiReturn = diff --git a/apps/dashboard/src/@/components/blocks/Avatars/GradientAvatar.stories.tsx b/apps/dashboard/src/@/components/blocks/Avatars/GradientAvatar.stories.tsx index 121e4c1b3b4..880893e091e 100644 --- a/apps/dashboard/src/@/components/blocks/Avatars/GradientAvatar.stories.tsx +++ b/apps/dashboard/src/@/components/blocks/Avatars/GradientAvatar.stories.tsx @@ -1,7 +1,9 @@ import type { Meta, StoryObj } from "@storybook/react"; import { useState } from "react"; -import { BadgeContainer } from "../../../../stories/utils"; -import { getThirdwebClient } from "../../../constants/thirdweb.server"; +import { + BadgeContainer, + storybookThirdwebClient, +} from "../../../../stories/utils"; import { Button } from "../../ui/button"; import { GradientAvatar } from "./GradientAvatar"; @@ -17,8 +19,6 @@ export const Variants: Story = { args: {}, }; -const client = getThirdwebClient(); - function Story() { return (
@@ -29,7 +29,7 @@ function Story() { id={undefined} src={undefined} className="size-20" - client={client} + client={storybookThirdwebClient} /> @@ -38,7 +38,7 @@ function Story() { id={"foo"} src={undefined} className="size-20" - client={client} + client={storybookThirdwebClient} /> @@ -47,7 +47,7 @@ function Story() { id={"foo"} src={""} className="size-20" - client={client} + client={storybookThirdwebClient} /> @@ -56,7 +56,7 @@ function Story() { id={"bar"} src={""} className="size-20" - client={client} + client={storybookThirdwebClient} /> @@ -65,7 +65,7 @@ function Story() { src="invalid-src" id={undefined} className="size-20" - client={client} + client={storybookThirdwebClient} /> @@ -74,7 +74,7 @@ function Story() { src="https://picsum.photos/200/300" id={undefined} className="size-20" - client={client} + client={storybookThirdwebClient} /> @@ -83,7 +83,7 @@ function Story() { src="ipfs://QmZbeJYEs7kCJHyQxjxU2SJUtjSAr4m87wzJFJUyWomKdj/Smily.svg" id={undefined} className="size-20" - client={client} + client={storybookThirdwebClient} /> @@ -123,7 +123,7 @@ function ToggleTest() { src={data?.src} id={data?.id} className="size-20" - client={client} + client={storybookThirdwebClient} /> @@ -132,7 +132,7 @@ function ToggleTest() { className="size-20" src={data ? "invalid-src" : undefined} id={undefined} - client={client} + client={storybookThirdwebClient} />
diff --git a/apps/dashboard/src/@/components/blocks/Avatars/ProjectAvatar.stories.tsx b/apps/dashboard/src/@/components/blocks/Avatars/ProjectAvatar.stories.tsx index 30674e33330..a39350dccc9 100644 --- a/apps/dashboard/src/@/components/blocks/Avatars/ProjectAvatar.stories.tsx +++ b/apps/dashboard/src/@/components/blocks/Avatars/ProjectAvatar.stories.tsx @@ -1,7 +1,9 @@ import type { Meta, StoryObj } from "@storybook/react"; import { useState } from "react"; -import { BadgeContainer } from "../../../../stories/utils"; -import { getThirdwebClient } from "../../../constants/thirdweb.server"; +import { + BadgeContainer, + storybookThirdwebClient, +} from "../../../../stories/utils"; import { Button } from "../../ui/button"; import { ProjectAvatar } from "./ProjectAvatar"; @@ -18,19 +20,25 @@ export const Variants: Story = { args: {}, }; -const client = getThirdwebClient(); - function Story() { return (

All images below are set with size-6 className

- + - + @@ -65,14 +73,18 @@ function ToggleTest() {

Src+Name is: {data ? "set" : "not set"}

- +
diff --git a/apps/dashboard/src/@/constants/thirdweb.client.ts b/apps/dashboard/src/@/constants/thirdweb.client.ts index 60e982e2159..731110348fb 100644 --- a/apps/dashboard/src/@/constants/thirdweb.client.ts +++ b/apps/dashboard/src/@/constants/thirdweb.client.ts @@ -2,12 +2,16 @@ import { useQuery } from "@tanstack/react-query"; import { useMemo } from "react"; import { useActiveAccount } from "thirdweb/react"; import type { GetAuthTokenResponse } from "../../app/api/auth/get-auth-token/route"; +import { LAST_USED_TEAM_ID } from "../../constants/cookies"; +import { getCookie } from "../../lib/cookie"; import { getThirdwebClient } from "./thirdweb.server"; // returns a thirdweb client with optional JWT passed i export function useThirdwebClient(jwt?: string) { const account = useActiveAccount(); + const lastUsedTeamId = getCookie(LAST_USED_TEAM_ID); + const query = useQuery({ queryKey: ["jwt", account?.address], // only enable the query if there is an account and no JWT is passed in directly @@ -33,8 +37,12 @@ export function useThirdwebClient(jwt?: string) { return useMemo( // prefer jwt from props over the one from the token query if it exists - () => getThirdwebClient(jwt || query.data), - [jwt, query.data], + () => + getThirdwebClient({ + jwt: jwt || query.data, + teamId: lastUsedTeamId, + }), + [jwt, query.data, lastUsedTeamId], ); } diff --git a/apps/dashboard/src/@/constants/thirdweb.server.ts b/apps/dashboard/src/@/constants/thirdweb.server.ts index cf73743d190..28cc1f3ac97 100644 --- a/apps/dashboard/src/@/constants/thirdweb.server.ts +++ b/apps/dashboard/src/@/constants/thirdweb.server.ts @@ -23,7 +23,14 @@ import { getZkPaymasterData } from "thirdweb/wallets/smart"; import { getVercelEnv } from "../../lib/vercel-utils"; // returns a thirdweb client with optional JWT passed in -export function getThirdwebClient(jwt?: string) { +export function getThirdwebClient( + options: + | { + jwt: string | null | undefined; + teamId: string | undefined; + } + | undefined, +) { if (getVercelEnv() !== "production") { // if not on production: run this when creating a client to set the domains setThirdwebDomains({ @@ -71,7 +78,8 @@ export function getThirdwebClient(jwt?: string) { } return createThirdwebClient({ - secretKey: jwt ? jwt : DASHBOARD_THIRDWEB_SECRET_KEY, + teamId: options?.teamId, + secretKey: options?.jwt ? options.jwt : DASHBOARD_THIRDWEB_SECRET_KEY, clientId: DASHBOARD_THIRDWEB_CLIENT_ID, config: { storage: { diff --git a/apps/dashboard/src/app/(dashboard)/(bridge)/bridge/components/client/UniversalBridgeEmbed.tsx b/apps/dashboard/src/app/(dashboard)/(bridge)/bridge/components/client/UniversalBridgeEmbed.tsx index ccc20d1cc5f..dbb2e1673e3 100644 --- a/apps/dashboard/src/app/(dashboard)/(bridge)/bridge/components/client/UniversalBridgeEmbed.tsx +++ b/apps/dashboard/src/app/(dashboard)/(bridge)/bridge/components/client/UniversalBridgeEmbed.tsx @@ -1,17 +1,21 @@ "use client"; -import { getThirdwebClient } from "@/constants/thirdweb.server"; + import { getSDKTheme } from "app/components/sdk-component-theme"; import { useV5DashboardChain } from "lib/v5-adapter"; import { useTheme } from "next-themes"; +import type { ThirdwebClient } from "thirdweb"; import { PayEmbed } from "thirdweb/react"; -export function UniversalBridgeEmbed({ chainId }: { chainId?: number }) { +export function UniversalBridgeEmbed({ + chainId, + client, +}: { chainId?: number; client: ThirdwebClient }) { const { theme } = useTheme(); const chain = useV5DashboardChain(chainId || 1); return ( }) { const { chainId } = searchParams; + const client = getThirdwebClient(undefined); return (
- +
{/* eslint-disable-next-line @next/next/no-img-element */} diff --git a/apps/dashboard/src/app/(dashboard)/(bridge)/routes/components/server/routelist-card.tsx b/apps/dashboard/src/app/(dashboard)/(bridge)/routes/components/server/routelist-card.tsx index 46774ad78bf..24ab0b5bc34 100644 --- a/apps/dashboard/src/app/(dashboard)/(bridge)/routes/components/server/routelist-card.tsx +++ b/apps/dashboard/src/app/(dashboard)/(bridge)/routes/components/server/routelist-card.tsx @@ -1,6 +1,6 @@ import { Card, CardContent, CardHeader } from "@/components/ui/card"; -import { getThirdwebClient } from "@/constants/thirdweb.server"; import { resolveSchemeWithErrorHandler } from "@/lib/resolveSchemeWithErrorHandler"; +import type { ThirdwebClient } from "thirdweb"; import { defineChain } from "thirdweb"; import { getChainMetadata } from "thirdweb/chains"; @@ -15,6 +15,7 @@ type RouteListCardProps = { destinationTokenIconUri?: string | null; destinationTokenSymbol: string; destinationTokenName: string; + client: ThirdwebClient; }; export async function RouteListCard({ @@ -26,6 +27,7 @@ export async function RouteListCard({ destinationTokenAddress, destinationTokenIconUri, destinationTokenName, + client, }: RouteListCardProps) { const [ originChain, @@ -40,13 +42,13 @@ export async function RouteListCard({ originTokenIconUri ? resolveSchemeWithErrorHandler({ uri: originTokenIconUri, - client: getThirdwebClient(), + client, }) : undefined, destinationTokenIconUri ? resolveSchemeWithErrorHandler({ uri: destinationTokenIconUri, - client: getThirdwebClient(), + client, }) : undefined, ]); diff --git a/apps/dashboard/src/app/(dashboard)/(bridge)/routes/components/server/routelist-row.tsx b/apps/dashboard/src/app/(dashboard)/(bridge)/routes/components/server/routelist-row.tsx index 27b68ca458f..aebf36e8418 100644 --- a/apps/dashboard/src/app/(dashboard)/(bridge)/routes/components/server/routelist-row.tsx +++ b/apps/dashboard/src/app/(dashboard)/(bridge)/routes/components/server/routelist-row.tsx @@ -1,7 +1,7 @@ import { CopyTextButton } from "@/components/ui/CopyTextButton"; import { TableCell, TableRow } from "@/components/ui/table"; -import { getThirdwebClient } from "@/constants/thirdweb.server"; import { resolveSchemeWithErrorHandler } from "@/lib/resolveSchemeWithErrorHandler"; +import type { ThirdwebClient } from "thirdweb"; import { defineChain, getChainMetadata } from "thirdweb/chains"; type RouteListRowProps = { @@ -15,6 +15,7 @@ type RouteListRowProps = { destinationTokenIconUri?: string | null; destinationTokenSymbol?: string; destinationTokenName?: string; + client: ThirdwebClient; }; export async function RouteListRow({ @@ -26,6 +27,7 @@ export async function RouteListRow({ destinationTokenAddress, destinationTokenIconUri, destinationTokenSymbol, + client, }: RouteListRowProps) { const [ originChain, @@ -40,13 +42,13 @@ export async function RouteListRow({ originTokenIconUri ? resolveSchemeWithErrorHandler({ uri: originTokenIconUri, - client: getThirdwebClient(), + client, }) : undefined, destinationTokenIconUri ? resolveSchemeWithErrorHandler({ uri: destinationTokenIconUri, - client: getThirdwebClient(), + client, }) : undefined, ]); diff --git a/apps/dashboard/src/app/(dashboard)/(bridge)/routes/components/server/routes-table.tsx b/apps/dashboard/src/app/(dashboard)/(bridge)/routes/components/server/routes-table.tsx index 645a8ade655..4423b278d24 100644 --- a/apps/dashboard/src/app/(dashboard)/(bridge)/routes/components/server/routes-table.tsx +++ b/apps/dashboard/src/app/(dashboard)/(bridge)/routes/components/server/routes-table.tsx @@ -6,6 +6,7 @@ import { TableHeader, TableRow, } from "@/components/ui/table"; +import { getThirdwebClient } from "@/constants/thirdweb.server"; import type { Address } from "thirdweb"; import { checksumAddress } from "thirdweb/utils"; import { getRoutes } from "../../../utils"; @@ -136,6 +137,7 @@ export async function RoutesData(props: { const startIndex = (activePage - 1) * pageSize; const endIndex = startIndex + pageSize; const paginatedRoutes = routesToRender.slice(startIndex, endIndex); + const client = getThirdwebClient(undefined); return ( <> @@ -170,6 +172,7 @@ export async function RoutesData(props: { destinationTokenIconUri={route.destinationToken.iconUri} destinationTokenSymbol={route.destinationToken.symbol} destinationTokenName={route.destinationToken.name} + client={client} /> ))} @@ -193,6 +196,7 @@ export async function RoutesData(props: { destinationTokenIconUri={route.destinationToken.iconUri} destinationTokenSymbol={route.destinationToken.symbol} destinationTokenName={route.destinationToken.name} + client={client} /> ))} diff --git a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/BuyFundsSection.tsx b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/BuyFundsSection.tsx index ea86946e9ab..64d81fda59b 100644 --- a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/BuyFundsSection.tsx +++ b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/BuyFundsSection.tsx @@ -1,12 +1,16 @@ import { ExternalLinkIcon } from "lucide-react"; import Link from "next/link"; +import type { ThirdwebClient } from "thirdweb"; import type { ChainMetadata } from "thirdweb/chains"; import { ChainIcon } from "../../../../components/server/chain-icon"; import { PayModalButton } from "../client/PayModal"; import { CreditCardIcon } from "../icons/CreditCardIcon"; import { SectionTitle } from "./SectionTitle"; -export function BuyFundsSection(props: { chain: ChainMetadata }) { +export function BuyFundsSection(props: { + chain: ChainMetadata; + client: ThirdwebClient; +}) { const sanitizedChainName = props.chain.name.replace("Mainnet", "").trim(); return ( @@ -18,6 +22,7 @@ export function BuyFundsSection(props: { chain: ChainMetadata }) {
diff --git a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/chain-header.tsx b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/chain-header.tsx index ab2140bae53..bd01374d3f0 100644 --- a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/chain-header.tsx +++ b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/chain-header.tsx @@ -1,6 +1,7 @@ import { Button } from "@/components/ui/button"; import { cn } from "@/lib/utils"; import Link from "next/link"; +import type { ThirdwebClient } from "thirdweb"; import type { ChainMetadata } from "thirdweb/chains"; import { mapV4ChainToV5Chain } from "../../../../../../../contexts/map-chains"; import { ChainIcon } from "../../../../components/server/chain-icon"; @@ -10,6 +11,7 @@ type ChainHeaderProps = { headerImageUrl?: string; logoUrl?: string; chain: ChainMetadata; + client: ThirdwebClient; }; // TODO: improve the behavior when clicking "Get started with thirdweb", currently just redirects to the dashboard @@ -39,6 +41,7 @@ export function ChainHeader(props: ChainHeaderProps) { {/* chain logo */}
diff --git a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/(chainPage)/opengraph-image.tsx b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/(chainPage)/opengraph-image.tsx index bbc548926b7..2a785888be1 100644 --- a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/(chainPage)/opengraph-image.tsx +++ b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/(chainPage)/opengraph-image.tsx @@ -77,9 +77,10 @@ export default async function Image({ ), // download the chain icon if there is one chain.icon?.url && hasWorkingChainIcon - ? download({ uri: chain.icon.url, client: getThirdwebClient() }).then( - (res) => res.arrayBuffer(), - ) + ? download({ + uri: chain.icon.url, + client: getThirdwebClient(undefined), + }).then((res) => res.arrayBuffer()) : undefined, // download the background image (based on chain) fetch( diff --git a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx index 1cd6f1e07bc..89722d94a56 100644 --- a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx +++ b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx @@ -1,5 +1,6 @@ import { CircleAlertIcon } from "lucide-react"; import { getRawAccount } from "../../../../account/settings/getAccount"; +import { getUserThirdwebClient } from "../../../../api/lib/getAuthToken"; import { getChain, getChainMetadata } from "../../utils"; import NextSteps from "./components/client/NextSteps"; import { BuyFundsSection } from "./components/server/BuyFundsSection"; @@ -18,6 +19,7 @@ export default async function Page(props: { const chainMetadata = await getChainMetadata(chain.chainId); const isDeprecated = chain.status === "deprecated"; + const client = await getUserThirdwebClient(); const account = await getRawAccount(); return ( @@ -42,9 +44,9 @@ export default async function Page(props: { {/* Faucet / Buy Funds */} {chain.testnet ? ( - + ) : chain.services.find((c) => c.service === "pay" && c.enabled) ? ( - + ) : null} {/* Chain Overview */} diff --git a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/components/list-button.tsx b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/components/list-button.tsx index d30fff1872a..4b382ba36db 100644 --- a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/components/list-button.tsx +++ b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/components/list-button.tsx @@ -10,12 +10,12 @@ import { } from "@/components/ui/sheet"; import { TabButtons } from "@/components/ui/tabs"; import { ListerOnly } from "@3rdweb-sdk/react/components/roles/lister-only"; -import { isAlchemySupported } from "lib/wallet/nfts/alchemy"; -import { isMoralisSupported } from "lib/wallet/nfts/moralis"; import { PlusIcon } from "lucide-react"; import { useState } from "react"; import type { ThirdwebContract } from "thirdweb"; import { useActiveAccount } from "thirdweb/react"; +import { isAlchemySupported } from "../../../../../../../lib/wallet/nfts/isAlchemySupported"; +import { isMoralisSupported } from "../../../../../../../lib/wallet/nfts/isMoralisSupported"; import { CreateListingsForm } from "./list-form"; interface CreateListingButtonProps { diff --git a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/components/list-form.tsx b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/components/list-form.tsx index 29f96dc3c99..68aee9001ad 100644 --- a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/components/list-form.tsx +++ b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/components/list-form.tsx @@ -18,8 +18,6 @@ import { SolidityInput } from "contract-ui/components/solidity-inputs"; import { useTrack } from "hooks/analytics/useTrack"; import { useAllChainsData } from "hooks/chains/allChains"; import { useTxNotifications } from "hooks/useTxNotifications"; -import { isAlchemySupported } from "lib/wallet/nfts/alchemy"; -import { isMoralisSupported } from "lib/wallet/nfts/moralis"; import type { WalletNFT } from "lib/wallet/nfts/types"; import { CircleAlertIcon, InfoIcon } from "lucide-react"; import Link from "next/link"; @@ -56,6 +54,8 @@ import { shortenAddress } from "thirdweb/utils"; import { FormErrorMessage, FormHelperText, FormLabel } from "tw-components"; import { NFTMediaWithEmptyState } from "tw-components/nft-media"; import { shortenIfAddress } from "utils/usedapp-external"; +import { isAlchemySupported } from "../../../../../../../lib/wallet/nfts/isAlchemySupported"; +import { isMoralisSupported } from "../../../../../../../lib/wallet/nfts/isMoralisSupported"; const LIST_FORM_ID = "marketplace-list-form"; diff --git a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/contract-metadata.tsx b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/contract-metadata.tsx index 316bb1a6e22..3b84562d93c 100644 --- a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/contract-metadata.tsx +++ b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/contract-metadata.tsx @@ -1,4 +1,3 @@ -import { getThirdwebClient } from "@/constants/thirdweb.server"; import { type DashboardContractMetadata, fetchDashboardContractMetadata, @@ -32,6 +31,7 @@ export function ContractMetadata({ chain={chain} address={contract.address} externalLinks={externalLinks} + client={contract.client} /> ); } @@ -43,7 +43,7 @@ export async function getContractMetadataHeaderData( fetchDashboardContractMetadata(contract), fetchPublishedContractsFromDeploy({ contract, - client: getThirdwebClient(), + client: contract.client, }), ]); diff --git a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/metadata-header.tsx b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/metadata-header.tsx index e398f70649f..550ff06169c 100644 --- a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/metadata-header.tsx +++ b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/metadata-header.tsx @@ -2,10 +2,10 @@ import { CopyAddressButton } from "@/components/ui/CopyAddressButton"; import { Button } from "@/components/ui/button"; -import { getThirdwebClient } from "@/constants/thirdweb.server"; import { ChainIconClient } from "components/icons/ChainIcon"; import { ExternalLinkIcon } from "lucide-react"; import Link from "next/link"; +import type { ThirdwebClient } from "thirdweb"; import type { ChainMetadata } from "thirdweb/chains"; import { MediaRenderer } from "thirdweb/react"; @@ -22,6 +22,7 @@ interface MetadataHeaderProps { }; chain: ChainMetadata; externalLinks?: ExternalLink[]; + client: ThirdwebClient; } export const MetadataHeader: React.FC = ({ @@ -29,6 +30,7 @@ export const MetadataHeader: React.FC = ({ data, chain, externalLinks, + client, }) => { const cleanedChainName = chain?.name?.replace("Mainnet", "").trim(); const validBlockExplorers = chain?.explorers @@ -56,7 +58,7 @@ export const MetadataHeader: React.FC = ({
m.name === "SuperChainInterop", ); + const client = coreContract.client; const addRowMutation = useMutation({ mutationFn: async (chain: { chainId: number; name: string }) => { if (coreContract.chain.id === chain.chainId) { @@ -122,7 +123,7 @@ export function DataTable({ const c = defineChain(chain.chainId); const code = await eth_getCode( getRpcClient({ - client: getThirdwebClient(), + client: client, chain: c, }), { address: coreContract.address }, @@ -261,7 +262,7 @@ export function DataTable({ return ( @@ -324,7 +325,7 @@ export function DataTable({ getCoreRowModel: getCoreRowModel(), }); - const deployContract = async (chainId: number) => { + const deployContract = async (chainId: number, client: ThirdwebClient) => { try { if (!activeAccount) { throw new Error("No active account"); @@ -332,7 +333,6 @@ export function DataTable({ // eslint-disable-next-line no-restricted-syntax const chain = defineChain(chainId); - const client = getThirdwebClient(); const salt = inputSalt || concatHex(["0x03", padHex("0x", { size: 31 })]).toString(); diff --git a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/layout.tsx b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/layout.tsx index eb0dcf4bfde..a89f6b8dd44 100644 --- a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/layout.tsx +++ b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/layout.tsx @@ -1,6 +1,5 @@ import { getProjects } from "@/api/projects"; import { getTeams } from "@/api/team"; -import { getThirdwebClient } from "@/constants/thirdweb.server"; import type { Metadata } from "next"; import { notFound } from "next/navigation"; import { localhost } from "thirdweb/chains"; @@ -12,6 +11,7 @@ import { shortenIfAddress } from "../../../../../utils/usedapp-external"; import { getAuthToken, getAuthTokenWalletAddress, + getUserThirdwebClient, } from "../../../../api/lib/getAuthToken"; import { NebulaFloatingChatButton } from "../../../../nebula-app/(app)/components/FloatingChat/FloatingChat"; import { ConfigureCustomChain } from "./_layout/ConfigureCustomChain"; @@ -52,7 +52,7 @@ export default async function Layout(props: { getAuthTokenWalletAddress(), ]); - const client = getThirdwebClient(); + const client = await getUserThirdwebClient(); const teamsAndProjects = await getTeamsAndProjectsIfLoggedIn(); if (contract.chain.id === localhost.id) { diff --git a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/batchMetadata.stories.tsx b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/batchMetadata.stories.tsx index 546fa983002..9ab2287dc14 100644 --- a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/batchMetadata.stories.tsx +++ b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/batchMetadata.stories.tsx @@ -1,10 +1,9 @@ import { Checkbox } from "@/components/ui/checkbox"; -import { getThirdwebClient } from "@/constants/thirdweb.server"; import type { Meta, StoryObj } from "@storybook/react"; import { useMutation } from "@tanstack/react-query"; import { useState } from "react"; import { toast } from "sonner"; -import { BadgeContainer } from "stories/utils"; +import { BadgeContainer, storybookThirdwebClient } from "stories/utils"; import { ZERO_ADDRESS } from "thirdweb"; import { ConnectButton, ThirdwebProvider } from "thirdweb/react"; import type { TransactionError } from "../../../../../../../contexts/error-handler"; @@ -70,7 +69,7 @@ function Component() {
- +
diff --git a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/claimable.stories.tsx b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/claimable.stories.tsx index 8f7ad37b1dc..9b6076735c4 100644 --- a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/claimable.stories.tsx +++ b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/claimable.stories.tsx @@ -6,7 +6,6 @@ import { SelectTrigger, SelectValue, } from "@/components/ui/select"; -import { getThirdwebClient } from "@/constants/thirdweb.server"; import type { Meta, StoryObj } from "@storybook/react"; import { useMutation } from "@tanstack/react-query"; import { subDays } from "date-fns"; @@ -15,6 +14,7 @@ import { toast } from "sonner"; import { NATIVE_TOKEN_ADDRESS, ZERO_ADDRESS } from "thirdweb"; import { ConnectButton, ThirdwebProvider } from "thirdweb/react"; import { checksumAddress } from "thirdweb/utils"; +import { storybookThirdwebClient } from "../../../../../../../stories/utils"; import { type ClaimConditionFormValues, type ClaimConditionValue, @@ -102,7 +102,7 @@ function Component() {
- +
diff --git a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/getModuleInstalledParams.ts b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/getModuleInstalledParams.ts index edc54cd8e1f..e942650ab21 100644 --- a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/getModuleInstalledParams.ts +++ b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/getModuleInstalledParams.ts @@ -1,21 +1,23 @@ -import { getThirdwebClient } from "@/constants/thirdweb.server"; import { fetchLatestPublishedContractVersion, fetchPublishedContractVersions, } from "components/contract-components/fetch-contracts-with-versions"; -import { isAddress } from "thirdweb"; +import { type ThirdwebClient, isAddress } from "thirdweb"; import type { FetchDeployMetadataResult } from "thirdweb/contract"; import { resolveAddress } from "thirdweb/extensions/ens"; import invariant from "tiny-invariant"; import type { ModuleMeta } from "./install-module-params"; -export async function getModuleInstalledParams(ext: ModuleMeta) { +export async function getModuleInstalledParams( + ext: ModuleMeta, + client: ThirdwebClient, +) { // get all versions of the module // if the publisher is an ens name, resolve it const publisherAddress = isAddress(ext.publisherAddress) ? ext.publisherAddress : await resolveAddress({ - client: getThirdwebClient(), + client, name: ext.publisherAddress, }); @@ -25,11 +27,13 @@ export async function getModuleInstalledParams(ext: ModuleMeta) { publishedModule = await fetchLatestPublishedContractVersion( publisherAddress, ext.moduleName, + client, ); } else { const allPublishedModules = await fetchPublishedContractVersions( publisherAddress, ext.moduleName, + client, ); publishedModule = allPublishedModules.find( diff --git a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/install-module-params.tsx b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/install-module-params.tsx index 18e29cff371..c43bc0981b6 100644 --- a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/install-module-params.tsx +++ b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/install-module-params.tsx @@ -1,3 +1,4 @@ +import { useThirdwebClient } from "@/constants/thirdweb.client"; import { FormControl } from "@chakra-ui/react"; import { useQuery } from "@tanstack/react-query"; import { SolidityInput } from "contract-ui/components/solidity-inputs"; @@ -20,12 +21,13 @@ export function useModuleInstallParams(props: { module?: ModuleMeta; isQueryEnabled: boolean; }) { + const client = useThirdwebClient(); const { module, isQueryEnabled } = props; return useQuery({ queryKey: ["useModuleInstallParams", module], queryFn: async () => { invariant(module, "module must be defined"); - return await getModuleInstalledParams(module); + return await getModuleInstalledParams(module, client); }, enabled: !!(isQueryEnabled && module), refetchOnWindowFocus: false, diff --git a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/mintable.stories.tsx b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/mintable.stories.tsx index 550b831564c..a018dd38eff 100644 --- a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/mintable.stories.tsx +++ b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/mintable.stories.tsx @@ -7,12 +7,11 @@ import { SelectTrigger, SelectValue, } from "@/components/ui/select"; -import { getThirdwebClient } from "@/constants/thirdweb.server"; import type { Meta, StoryObj } from "@storybook/react"; import { useMutation } from "@tanstack/react-query"; import { useState } from "react"; import { toast } from "sonner"; -import { BadgeContainer } from "stories/utils"; +import { BadgeContainer, storybookThirdwebClient } from "stories/utils"; import { ConnectButton, ThirdwebProvider } from "thirdweb/react"; import { type MintFormValues, @@ -75,7 +74,7 @@ function Component() {
- +
diff --git a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/openEditionMetadata.stories.tsx b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/openEditionMetadata.stories.tsx index 6d7d0ee3c72..91ecf0d1138 100644 --- a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/openEditionMetadata.stories.tsx +++ b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/openEditionMetadata.stories.tsx @@ -1,10 +1,9 @@ import { Checkbox } from "@/components/ui/checkbox"; -import { getThirdwebClient } from "@/constants/thirdweb.server"; import type { Meta, StoryObj } from "@storybook/react"; import { useMutation } from "@tanstack/react-query"; import { useState } from "react"; import { toast } from "sonner"; -import { BadgeContainer } from "stories/utils"; +import { BadgeContainer, storybookThirdwebClient } from "stories/utils"; import { ConnectButton, ThirdwebProvider } from "thirdweb/react"; import { OpenEditionMetadataModuleUI, @@ -56,7 +55,7 @@ function Component() {
- +
diff --git a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/royalty.stories.tsx b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/royalty.stories.tsx index 83b0f3769cb..38e9b03e9be 100644 --- a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/royalty.stories.tsx +++ b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/royalty.stories.tsx @@ -1,10 +1,9 @@ import { Checkbox } from "@/components/ui/checkbox"; -import { getThirdwebClient } from "@/constants/thirdweb.server"; import type { Meta, StoryObj } from "@storybook/react"; import { useMutation } from "@tanstack/react-query"; import { useState } from "react"; import { toast } from "sonner"; -import { BadgeContainer } from "stories/utils"; +import { BadgeContainer, storybookThirdwebClient } from "stories/utils"; import { ConnectButton, ThirdwebProvider } from "thirdweb/react"; import { type DefaultRoyaltyFormValues, @@ -70,7 +69,7 @@ function Component() {
- +
diff --git a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/transferable.stories.tsx b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/transferable.stories.tsx index 50d57fa3afd..e047028ff2e 100644 --- a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/transferable.stories.tsx +++ b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/transferable.stories.tsx @@ -1,10 +1,9 @@ import { Checkbox } from "@/components/ui/checkbox"; -import { getThirdwebClient } from "@/constants/thirdweb.server"; import type { Meta, StoryObj } from "@storybook/react"; import { useMutation } from "@tanstack/react-query"; import { useState } from "react"; import { toast } from "sonner"; -import { BadgeContainer } from "stories/utils"; +import { BadgeContainer, storybookThirdwebClient } from "stories/utils"; import { ConnectButton, ThirdwebProvider } from "thirdweb/react"; import { type TransferableModuleFormValues, @@ -74,7 +73,7 @@ function Component() {
- +
diff --git a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/published-by-ui.tsx b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/published-by-ui.tsx index 4e70eaae6e1..02702516bf9 100644 --- a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/published-by-ui.tsx +++ b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/published-by-ui.tsx @@ -54,7 +54,7 @@ export async function getPublishedByCardProps(params: { let publisherAddressOrEns = publishedContractToShow.publisher; if (!isValidENSName(publishedContractToShow.publisher)) { try { - const res = await resolveEns(publishedContractToShow.publisher); + const res = await resolveEns(publishedContractToShow.publisher, client); if (res.ensName) { publisherAddressOrEns = res.ensName; } @@ -147,6 +147,7 @@ export function PublishedByUI(props: { publisher: string; version: string | undefined; isBeta: boolean; + client: ThirdwebClient; }) { return ( ); } diff --git a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/published-by.server.tsx b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/published-by.server.tsx index 653ebd266fd..9a9f392bda1 100644 --- a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/published-by.server.tsx +++ b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/published-by.server.tsx @@ -1,4 +1,3 @@ -import { getThirdwebClient } from "@/constants/thirdweb.server"; import type { ThirdwebContract } from "thirdweb"; import { getAuthTokenWalletAddress } from "../../../../../../api/lib/getAuthToken"; import { PublishedByUI, getPublishedByCardProps } from "./published-by-ui"; @@ -8,12 +7,11 @@ interface PublishedByProps { } export const PublishedBy: React.FC = async ({ contract }) => { - const client = getThirdwebClient(); const address = await getAuthTokenWalletAddress(); const props = await getPublishedByCardProps({ address, contract, - client, + client: contract.client, }); if (!props) { @@ -27,6 +25,7 @@ export const PublishedBy: React.FC = async ({ contract }) => { name={props.name} publisher={props.publisher} version={props.version} + client={contract.client} /> ); }; diff --git a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/tx/[txHash]/page.tsx b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/tx/[txHash]/page.tsx index 750a2c7d72c..73c16296572 100644 --- a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/tx/[txHash]/page.tsx +++ b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/tx/[txHash]/page.tsx @@ -1,6 +1,5 @@ import { Badge } from "@/components/ui/badge"; import { Separator } from "@/components/ui/separator"; -import { getThirdwebClient } from "@/constants/thirdweb.server"; import { mapV4ChainToV5Chain } from "contexts/map-chains"; import { ZERO_ADDRESS, toTokens } from "thirdweb"; import { @@ -10,14 +9,14 @@ import { getRpcClient, } from "thirdweb/rpc"; import { hexToNumber, shortenAddress, toEther } from "thirdweb/utils"; +import { getUserThirdwebClient } from "../../../../../api/lib/getAuthToken"; import { getChain } from "../../../utils"; export default async function Page(props: { params: Promise<{ chain_id: string; txHash: `0x${string}` }>; }) { const params = await props.params; - // consider if we want to pass the JWT here, likely no need to do it but we could? - const client = getThirdwebClient(); + const client = await getUserThirdwebClient(); const chain = await getChain(params.chain_id); const rpcRequest = getRpcClient({ diff --git a/apps/dashboard/src/app/(dashboard)/(chain)/chainlist/[chain_type]/page.tsx b/apps/dashboard/src/app/(dashboard)/(chain)/chainlist/[chain_type]/page.tsx index cab118039a2..448b414bd7f 100644 --- a/apps/dashboard/src/app/(dashboard)/(chain)/chainlist/[chain_type]/page.tsx +++ b/apps/dashboard/src/app/(dashboard)/(chain)/chainlist/[chain_type]/page.tsx @@ -14,7 +14,10 @@ import { import { ChevronDownIcon } from "lucide-react"; import { headers } from "next/headers"; import Link from "next/link"; -import { getAuthToken } from "../../../../api/lib/getAuthToken"; +import { + getAuthToken, + getUserThirdwebClient, +} from "../../../../api/lib/getAuthToken"; import { AllFilters, ChainOptionsFilter, @@ -80,6 +83,8 @@ export default async function ChainListLayout(props: { ? "table" : "grid"; + const client = await getUserThirdwebClient(); + return ( <>
@@ -150,6 +155,7 @@ export default async function ChainListLayout(props: { searchParams={searchParams} activeView={activeView} isLoggedIn={!!authToken} + client={client} /> diff --git a/apps/dashboard/src/app/(dashboard)/(chain)/chainlist/components/server/chain-table.tsx b/apps/dashboard/src/app/(dashboard)/(chain)/chainlist/components/server/chain-table.tsx index 51fafdfe7cb..47d48c6c6cf 100644 --- a/apps/dashboard/src/app/(dashboard)/(chain)/chainlist/components/server/chain-table.tsx +++ b/apps/dashboard/src/app/(dashboard)/(chain)/chainlist/components/server/chain-table.tsx @@ -7,6 +7,7 @@ import { TableRow, } from "@/components/ui/table"; import Fuse from "fuse.js"; +import type { ThirdwebClient } from "thirdweb"; import { StarButton } from "../../../components/client/star-button"; import type { ChainMetadataWithServices, @@ -141,6 +142,7 @@ export async function ChainsData(props: { searchParams: SearchParams; activeView: "table" | "grid"; isLoggedIn: boolean; + client: ThirdwebClient; }) { const { chainsToRender, totalCount, filteredCount } = await getChainsToRender( props.searchParams, @@ -177,6 +179,7 @@ export async function ChainsData(props: { {paginatedChains.map((chain) => ( (
  • - +
    {favoriteButton &&
    {favoriteButton}
    } - +
    @@ -76,6 +81,7 @@ export default async function ChainListPage(props: { searchParams={searchParams} activeView={activeView} isLoggedIn={!!authToken} + client={client} /> ); diff --git a/apps/dashboard/src/app/(dashboard)/(chain)/components/server/chain-icon.tsx b/apps/dashboard/src/app/(dashboard)/(chain)/components/server/chain-icon.tsx index e57a1c77945..e4e847c7bad 100644 --- a/apps/dashboard/src/app/(dashboard)/(chain)/components/server/chain-icon.tsx +++ b/apps/dashboard/src/app/(dashboard)/(chain)/components/server/chain-icon.tsx @@ -1,20 +1,21 @@ /* eslint-disable @next/next/no-img-element */ import "server-only"; import { DASHBOARD_THIRDWEB_SECRET_KEY } from "@/constants/env"; -import { getThirdwebClient } from "@/constants/thirdweb.server"; import { resolveSchemeWithErrorHandler } from "@/lib/resolveSchemeWithErrorHandler"; import { cn } from "@/lib/utils"; +import type { ThirdwebClient } from "thirdweb"; import { fallbackChainIcon } from "../../../../../utils/chain-icons"; export async function ChainIcon(props: { iconUrl?: string; className?: string; + client: ThirdwebClient; }) { if (props.iconUrl) { let imageLink = fallbackChainIcon; const resolved = resolveSchemeWithErrorHandler({ - client: getThirdwebClient(), + client: props.client, uri: props.iconUrl, }); diff --git a/apps/dashboard/src/app/(dashboard)/contracts/deploy/[compiler_uri]/page.tsx b/apps/dashboard/src/app/(dashboard)/contracts/deploy/[compiler_uri]/page.tsx index b49bdd73970..42ff9f34fd5 100644 --- a/apps/dashboard/src/app/(dashboard)/contracts/deploy/[compiler_uri]/page.tsx +++ b/apps/dashboard/src/app/(dashboard)/contracts/deploy/[compiler_uri]/page.tsx @@ -1,6 +1,6 @@ -import { getThirdwebClient } from "@/constants/thirdweb.server"; import { notFound } from "next/navigation"; import { fetchDeployMetadata } from "thirdweb/contract"; +import { getUserThirdwebClient } from "../../../../api/lib/getAuthToken"; import { DeployContractInfo } from "../../../published-contract/components/contract-info"; import { DeployFormForUri } from "../../../published-contract/components/uri-based-deploy"; @@ -13,8 +13,10 @@ type DirectDeployPageProps = { export default async function DirectDeployPage(props: DirectDeployPageProps) { const params = await props.params; const parsedUri = decodeURIComponent(params.compiler_uri); + const client = await getUserThirdwebClient(); + const metadata = await fetchDeployMetadata({ - client: getThirdwebClient(), + client, // force `ipfs://` prefix uri: parsedUri.startsWith("ipfs://") ? parsedUri : `ipfs://${parsedUri}`, }).catch(() => null); @@ -30,6 +32,7 @@ export default async function DirectDeployPage(props: DirectDeployPageProps) { displayName={metadata.displayName} description={metadata.description} logo={metadata.logo} + client={client} /> }> - +
    ); diff --git a/apps/dashboard/src/app/(dashboard)/contracts/publish/[publish_uri]/page.tsx b/apps/dashboard/src/app/(dashboard)/contracts/publish/[publish_uri]/page.tsx index 5ec794acb43..ef084510458 100644 --- a/apps/dashboard/src/app/(dashboard)/contracts/publish/[publish_uri]/page.tsx +++ b/apps/dashboard/src/app/(dashboard)/contracts/publish/[publish_uri]/page.tsx @@ -1,10 +1,10 @@ import { ChakraProviderSetup } from "@/components/ChakraProviderSetup"; import { getActiveAccountCookie, getJWTCookie } from "@/constants/cookie"; -import { getThirdwebClient } from "@/constants/thirdweb.server"; import { ContractPublishForm } from "components/contract-components/contract-publish-form"; import { revalidatePath } from "next/cache"; import { notFound, redirect } from "next/navigation"; import { fetchDeployMetadata } from "thirdweb/contract"; +import { getUserThirdwebClient } from "../../../../api/lib/getAuthToken"; import { getLatestPublishedContractsWithPublisherMapping } from "../../../published-contract/[publisher]/[contract_id]/utils/getPublishedContractsWithPublisherMapping"; type DirectDeployPageProps = { @@ -22,9 +22,10 @@ export default async function PublishContractPage( ? decodedPublishUri : `ipfs://${decodedPublishUri}`; + const client = await getUserThirdwebClient(); const publishMetadataFromUri = await fetchDeployMetadata({ uri: publishUri, - client: getThirdwebClient(), + client, }).catch(() => null); if (!publishMetadataFromUri) { @@ -50,6 +51,7 @@ export default async function PublishContractPage( await getLatestPublishedContractsWithPublisherMapping({ publisher: address, contract_id: publishMetadataFromUri.name, + client, }); if (publishedContract) { diff --git a/apps/dashboard/src/app/(dashboard)/contracts/publish/page.tsx b/apps/dashboard/src/app/(dashboard)/contracts/publish/page.tsx index e5eebee4511..ae672fddb8e 100644 --- a/apps/dashboard/src/app/(dashboard)/contracts/publish/page.tsx +++ b/apps/dashboard/src/app/(dashboard)/contracts/publish/page.tsx @@ -3,6 +3,7 @@ import { DeployableContractTable } from "components/contract-components/contract import Link from "next/link"; import { notFound } from "next/navigation"; import { Suspense } from "react"; +import { getUserThirdwebClient } from "../../../api/lib/getAuthToken"; export default async function PublishMultipleContractsPage(props: { searchParams?: Promise<{ @@ -11,6 +12,7 @@ export default async function PublishMultipleContractsPage(props: { }) { const searchParams = await props.searchParams; const ipfsHashes = searchParams?.ipfs; + const client = await getUserThirdwebClient(); if (!ipfsHashes || !Array.isArray(ipfsHashes) || ipfsHashes.length === 0) { notFound(); @@ -35,7 +37,11 @@ export default async function PublishMultipleContractsPage(props: {
    }> - +
    ); diff --git a/apps/dashboard/src/app/(dashboard)/explore/[category]/page.tsx b/apps/dashboard/src/app/(dashboard)/explore/[category]/page.tsx index 97a27b5d640..2ac822e4a66 100644 --- a/apps/dashboard/src/app/(dashboard)/explore/[category]/page.tsx +++ b/apps/dashboard/src/app/(dashboard)/explore/[category]/page.tsx @@ -16,11 +16,13 @@ import type { Metadata } from "next"; import Link from "next/link"; import { notFound } from "next/navigation"; import { Suspense } from "react"; +import type { ThirdwebClient } from "thirdweb"; type ExploreCategoryPageProps = { params: Promise<{ category: string; }>; + client: ThirdwebClient; }; export async function generateMetadata( @@ -102,6 +104,7 @@ export default async function ExploreCategoryPage( key={publisher + contractId + overrides?.title} >
    @@ -37,7 +40,7 @@ export default async function ExplorePage() { {Math.floor(EXPLORE_PAGE_DATA.length / 2) === idx && ( )} - + ))}
    diff --git a/apps/dashboard/src/app/(dashboard)/profile/[addressOrEns]/ProfileUI.tsx b/apps/dashboard/src/app/(dashboard)/profile/[addressOrEns]/ProfileUI.tsx index ae14e98da8b..d4a78065d36 100644 --- a/apps/dashboard/src/app/(dashboard)/profile/[addressOrEns]/ProfileUI.tsx +++ b/apps/dashboard/src/app/(dashboard)/profile/[addressOrEns]/ProfileUI.tsx @@ -1,14 +1,16 @@ import { Spinner } from "@/components/ui/Spinner/Spinner"; import { fetchPublishedContracts } from "components/contract-components/fetchPublishedContracts"; import { Suspense } from "react"; +import type { ThirdwebClient } from "thirdweb"; import { ProfileHeader } from "./components/profile-header"; import { PublishedContracts } from "./components/published-contracts"; export function ProfileUI(props: { profileAddress: string; ensName: string | undefined; + client: ThirdwebClient; }) { - const { profileAddress, ensName } = props; + const { profileAddress, ensName, client } = props; return (
    @@ -25,6 +27,7 @@ export function ProfileUI(props: {
    @@ -37,10 +40,12 @@ export function ProfileUI(props: { async function AsyncPublishedContracts(props: { publisherAddress: string; publisherEnsName: string | undefined; + client: ThirdwebClient; }) { - const publishedContracts = await fetchPublishedContracts( - props.publisherAddress, - ); + const publishedContracts = await fetchPublishedContracts({ + address: props.publisherAddress, + client: props.client, + }); if (publishedContracts.length === 0) { return ( @@ -54,6 +59,7 @@ async function AsyncPublishedContracts(props: { ); } diff --git a/apps/dashboard/src/app/(dashboard)/profile/[addressOrEns]/components/PublishedContractTable.tsx b/apps/dashboard/src/app/(dashboard)/profile/[addressOrEns]/components/PublishedContractTable.tsx index 026f9c33411..afae10b7c64 100644 --- a/apps/dashboard/src/app/(dashboard)/profile/[addressOrEns]/components/PublishedContractTable.tsx +++ b/apps/dashboard/src/app/(dashboard)/profile/[addressOrEns]/components/PublishedContractTable.tsx @@ -18,12 +18,14 @@ import { ShieldCheckIcon } from "lucide-react"; import Link from "next/link"; import { useMemo } from "react"; import { type Column, type Row, useTable } from "react-table"; +import type { ThirdwebClient } from "thirdweb"; import type { PublishedContractDetails } from "../../../../../components/contract-components/hooks"; interface PublishedContractTableProps { contractDetails: ContractDataInput[]; footer?: React.ReactNode; publisherEnsName: string | undefined; + client: ThirdwebClient; } type ContractDataInput = PublishedContractDetails; @@ -57,7 +59,7 @@ export function PublishedContractTable(props: PublishedContractTableProps) { Cell: (cell: any) => ( } @@ -114,7 +116,7 @@ export function PublishedContractTable(props: PublishedContractTableProps) { className="relative z-10 h-auto w-auto p-2" > >; publisherEnsName: string | undefined; + client: ThirdwebClient; } export const PublishedContracts: React.FC = ({ limit = 10, publishedContracts, publisherEnsName, + client, }) => { const [showMoreLimit, setShowMoreLimit] = useState(10); const slicedData = publishedContracts.slice(0, showMoreLimit); return ( ); } export async function generateMetadata(props: PageProps): Promise { const params = await props.params; - const resolvedInfo = await resolveAddressAndEns(params.addressOrEns); + const client = getThirdwebClient(undefined); + const resolvedInfo = await resolveAddressAndEns(params.addressOrEns, client); if (!resolvedInfo) { return notFound(); diff --git a/apps/dashboard/src/app/(dashboard)/profile/[addressOrEns]/resolveAddressAndEns.tsx b/apps/dashboard/src/app/(dashboard)/profile/[addressOrEns]/resolveAddressAndEns.tsx index fb6579422d0..3265dc743f7 100644 --- a/apps/dashboard/src/app/(dashboard)/profile/[addressOrEns]/resolveAddressAndEns.tsx +++ b/apps/dashboard/src/app/(dashboard)/profile/[addressOrEns]/resolveAddressAndEns.tsx @@ -1,4 +1,4 @@ -import { getAddress, isAddress } from "thirdweb"; +import { type ThirdwebClient, getAddress, isAddress } from "thirdweb"; import { isValidENSName } from "thirdweb/utils"; import { mapThirdwebPublisher } from "../../../../components/contract-components/fetch-contracts-with-versions"; import { resolveEns } from "../../../../lib/ens"; @@ -9,9 +9,10 @@ type ResolvedAddressInfo = { }; export async function resolveAddressAndEns( addressOrEns: string, + client: ThirdwebClient, ): Promise { if (isAddress(addressOrEns)) { - const res = await resolveEns(addressOrEns).catch(() => null); + const res = await resolveEns(addressOrEns, client).catch(() => null); return { address: getAddress(addressOrEns), ensName: res?.ensName || undefined, @@ -20,7 +21,7 @@ export async function resolveAddressAndEns( if (isValidENSName(addressOrEns)) { const mappedEns = mapThirdwebPublisher(addressOrEns); - const res = await resolveEns(mappedEns).catch(() => null); + const res = await resolveEns(mappedEns, client).catch(() => null); if (res?.address) { return { address: getAddress(res?.address), diff --git a/apps/dashboard/src/app/(dashboard)/published-contract/[publisher]/[contract_id]/[version]/deploy/page.tsx b/apps/dashboard/src/app/(dashboard)/published-contract/[publisher]/[contract_id]/[version]/deploy/page.tsx index ed97daf37e1..d8955a4cc09 100644 --- a/apps/dashboard/src/app/(dashboard)/published-contract/[publisher]/[contract_id]/[version]/deploy/page.tsx +++ b/apps/dashboard/src/app/(dashboard)/published-contract/[publisher]/[contract_id]/[version]/deploy/page.tsx @@ -1,3 +1,4 @@ +import { getUserThirdwebClient } from "../../../../../../api/lib/getAuthToken"; import { DeployFormForPublishInfo } from "../../../../components/publish-based-deploy"; import { moduleFromBase64 } from "../../../../utils/module-base-64"; @@ -21,5 +22,10 @@ export default async function PublishedContractVersionDeployPage(props: { const modules = moduleParam?.map((m) => moduleFromBase64(m)).filter((m) => m !== null) || []; - return ; + + const client = await getUserThirdwebClient(); + + return ( + + ); } diff --git a/apps/dashboard/src/app/(dashboard)/published-contract/[publisher]/[contract_id]/[version]/opengraph-image.tsx b/apps/dashboard/src/app/(dashboard)/published-contract/[publisher]/[contract_id]/[version]/opengraph-image.tsx index 9f9d25d4428..0976b5ba077 100644 --- a/apps/dashboard/src/app/(dashboard)/published-contract/[publisher]/[contract_id]/[version]/opengraph-image.tsx +++ b/apps/dashboard/src/app/(dashboard)/published-contract/[publisher]/[contract_id]/[version]/opengraph-image.tsx @@ -20,16 +20,17 @@ export default async function Image(props: { version: string; }; }) { - const client = getThirdwebClient(); + const client = getThirdwebClient(undefined); const { publisher, contract_id } = props.params; const [publishedContracts, socialProfiles] = await Promise.all([ getPublishedContractsWithPublisherMapping({ publisher: publisher, contract_id: contract_id, + client, }), getSocialProfiles({ - address: (await resolveEns(publisher)).address || publisher, + address: (await resolveEns(publisher, client)).address || publisher, client, }), ]); diff --git a/apps/dashboard/src/app/(dashboard)/published-contract/[publisher]/[contract_id]/[version]/page.tsx b/apps/dashboard/src/app/(dashboard)/published-contract/[publisher]/[contract_id]/[version]/page.tsx index 9f7fa2820ad..c755c3cb8d5 100644 --- a/apps/dashboard/src/app/(dashboard)/published-contract/[publisher]/[contract_id]/[version]/page.tsx +++ b/apps/dashboard/src/app/(dashboard)/published-contract/[publisher]/[contract_id]/[version]/page.tsx @@ -1,6 +1,5 @@ import { ChakraProviderSetup } from "@/components/ChakraProviderSetup"; import { Separator } from "@/components/ui/separator"; -import { getThirdwebClient } from "@/constants/thirdweb.server"; import { SimpleGrid } from "@chakra-ui/react"; import { fetchPublishedContractVersions } from "components/contract-components/fetch-contracts-with-versions"; import { PublishedContract } from "components/contract-components/published-contract"; @@ -8,9 +7,9 @@ import { notFound } from "next/navigation"; import { isAddress } from "thirdweb"; import { resolveAddress } from "thirdweb/extensions/ens"; import { getRawAccount } from "../../../../../account/settings/getAccount"; +import { getUserThirdwebClient } from "../../../../../api/lib/getAuthToken"; import { PublishedActions } from "../../../components/contract-actions-published.client"; import { DeployContractHeader } from "../../../components/contract-header"; - function mapThirdwebPublisher(publisher: string) { if (publisher === "thirdweb.eth") { return "deployer.thirdweb.eth"; @@ -32,13 +31,14 @@ export default async function PublishedContractPage( const params = await props.params; // resolve ENS if required let publisherAddress: string | undefined = undefined; + const client = await getUserThirdwebClient(); if (isAddress(params.publisher)) { publisherAddress = params.publisher; } else { try { publisherAddress = await resolveAddress({ - client: getThirdwebClient(), + client, name: mapThirdwebPublisher(params.publisher), }); } catch { @@ -54,6 +54,7 @@ export default async function PublishedContractPage( const publishedContractVersions = await fetchPublishedContractVersions( publisherAddress, params.contract_id, + client, ); // determine the "active" version of the contract based on the version that is passed @@ -73,6 +74,7 @@ export default async function PublishedContractPage( {...params} allVersions={publishedContractVersions} activeVersion={publishedContract} + client={client} > moduleFromBase64(m)).filter((m) => m !== null) || []; - return ; + const client = await getUserThirdwebClient(); + + return ( + + ); } diff --git a/apps/dashboard/src/app/(dashboard)/published-contract/[publisher]/[contract_id]/layout.tsx b/apps/dashboard/src/app/(dashboard)/published-contract/[publisher]/[contract_id]/layout.tsx index 476a9cae76d..6628a4fbcae 100644 --- a/apps/dashboard/src/app/(dashboard)/published-contract/[publisher]/[contract_id]/layout.tsx +++ b/apps/dashboard/src/app/(dashboard)/published-contract/[publisher]/[contract_id]/layout.tsx @@ -1,3 +1,4 @@ +import { getThirdwebClient } from "@/constants/thirdweb.server"; import { PublishedContractBreadcrumbs } from "./components/breadcrumbs.client"; import { getLatestPublishedContractsWithPublisherMapping } from "./utils/getPublishedContractsWithPublisherMapping"; @@ -23,6 +24,7 @@ export async function generateMetadata(props: { params: Promise }) { await getLatestPublishedContractsWithPublisherMapping({ publisher: publisher, contract_id: contract_id, + client: getThirdwebClient(undefined), }); if (!publishedContract) { diff --git a/apps/dashboard/src/app/(dashboard)/published-contract/[publisher]/[contract_id]/opengraph-image.tsx b/apps/dashboard/src/app/(dashboard)/published-contract/[publisher]/[contract_id]/opengraph-image.tsx index 5828e050ded..645cd3d1752 100644 --- a/apps/dashboard/src/app/(dashboard)/published-contract/[publisher]/[contract_id]/opengraph-image.tsx +++ b/apps/dashboard/src/app/(dashboard)/published-contract/[publisher]/[contract_id]/opengraph-image.tsx @@ -19,16 +19,17 @@ export default async function Image(props: { contract_id: string; }; }) { - const client = getThirdwebClient(); + const client = getThirdwebClient(undefined); const { publisher, contract_id } = props.params; const [publishedContract, socialProfiles] = await Promise.all([ getLatestPublishedContractsWithPublisherMapping({ publisher: publisher, contract_id: contract_id, + client, }), getSocialProfiles({ - address: (await resolveEns(publisher)).address || publisher, + address: (await resolveEns(publisher, client)).address || publisher, client, }), ]); diff --git a/apps/dashboard/src/app/(dashboard)/published-contract/[publisher]/[contract_id]/page.tsx b/apps/dashboard/src/app/(dashboard)/published-contract/[publisher]/[contract_id]/page.tsx index 61cc382ddeb..e7170ca754c 100644 --- a/apps/dashboard/src/app/(dashboard)/published-contract/[publisher]/[contract_id]/page.tsx +++ b/apps/dashboard/src/app/(dashboard)/published-contract/[publisher]/[contract_id]/page.tsx @@ -3,6 +3,7 @@ import { Separator } from "@/components/ui/separator"; import { notFound } from "next/navigation"; import { PublishedContract } from "../../../../../components/contract-components/published-contract"; import { getRawAccount } from "../../../../account/settings/getAccount"; +import { getUserThirdwebClient } from "../../../../api/lib/getAuthToken"; import { PublishedActions } from "../../components/contract-actions-published.client"; import { DeployContractHeader } from "../../components/contract-header"; import { getPublishedContractsWithPublisherMapping } from "./utils/getPublishedContractsWithPublisherMapping"; @@ -18,10 +19,12 @@ export default async function PublishedContractPage( props: PublishedContractDeployPageProps, ) { const params = await props.params; + const client = await getUserThirdwebClient(); const publishedContractVersions = await getPublishedContractsWithPublisherMapping({ publisher: params.publisher, contract_id: params.contract_id, + client, }); if (!publishedContractVersions) { @@ -42,6 +45,7 @@ export default async function PublishedContractPage( {...params} allVersions={publishedContractVersions} activeVersion={publishedContract} + client={client} > res.arrayBuffer()); - const client = getThirdwebClient(); + const client = getThirdwebClient(undefined); const [ inter400, diff --git a/apps/dashboard/src/app/(dashboard)/published-contract/components/contract-header.tsx b/apps/dashboard/src/app/(dashboard)/published-contract/components/contract-header.tsx index 1c6ba08b8d4..46e48a75481 100644 --- a/apps/dashboard/src/app/(dashboard)/published-contract/components/contract-header.tsx +++ b/apps/dashboard/src/app/(dashboard)/published-contract/components/contract-header.tsx @@ -1,5 +1,6 @@ "use client"; import type { PropsWithChildren } from "react"; +import type { ThirdwebClient } from "thirdweb"; import type { PublishedContractWithVersion } from "../../../../components/contract-components/fetch-contracts-with-versions"; import { ModuleList } from "../[publisher]/[contract_id]/components/module-list.client"; import { DeployContractInfo } from "./contract-info"; @@ -11,6 +12,7 @@ type DeployContractHeaderProps = { version?: string; allVersions: PublishedContractWithVersion[]; activeVersion: PublishedContractWithVersion; + client: ThirdwebClient; }; export function DeployContractHeader( @@ -21,6 +23,7 @@ export function DeployContractHeader(
    ; + client: ThirdwebClient; }; function mapThirdwebPublisher(publisher: string) { @@ -25,7 +25,7 @@ function mapThirdwebPublisher(publisher: string) { } export async function DeployFormForPublishInfo(props: PublishBasedDeployProps) { - const client = getThirdwebClient(); + const client = props.client; // resolve ENS if required const publisherAddress = isAddress(props.publisher) ? props.publisher @@ -36,9 +36,9 @@ export async function DeployFormForPublishInfo(props: PublishBasedDeployProps) { // get all the published versions of the contract const [publishedContractVersions, ...modules] = await Promise.all([ - fetchPublishedContractVersions(publisherAddress, props.contract_id), + fetchPublishedContractVersions(publisherAddress, props.contract_id, client), ...(props.modules || []).map((m) => - fetchPublishedContractVersion(m.publisher, m.moduleId, m.version), + fetchPublishedContractVersion(m.publisher, m.moduleId, client, m.version), ), ]); diff --git a/apps/dashboard/src/app/(dashboard)/published-contract/page.tsx b/apps/dashboard/src/app/(dashboard)/published-contract/page.tsx index 5a2bd8f5c87..960d5a3a7e5 100644 --- a/apps/dashboard/src/app/(dashboard)/published-contract/page.tsx +++ b/apps/dashboard/src/app/(dashboard)/published-contract/page.tsx @@ -1,6 +1,6 @@ -import { getThirdwebClient } from "@/constants/thirdweb.server"; import { redirect } from "next/navigation"; import { fetchDeployMetadata } from "thirdweb/contract"; +import { getUserThirdwebClient } from "../../api/lib/getAuthToken"; export default async function Page(props: { searchParams: Promise<{ @@ -13,8 +13,10 @@ export default async function Page(props: { return redirect("/team"); } + const client = await getUserThirdwebClient(); + const contractMetadata = await fetchDeployMetadata({ - client: getThirdwebClient(), + client, // force `ipfs://` prefix uri: searchParams.uri.startsWith("ipfs://") ? searchParams.uri diff --git a/apps/dashboard/src/app/account/components/AccountHeaderUI.stories.tsx b/apps/dashboard/src/app/account/components/AccountHeaderUI.stories.tsx index c70976303d7..6dfb1dd3b43 100644 --- a/apps/dashboard/src/app/account/components/AccountHeaderUI.stories.tsx +++ b/apps/dashboard/src/app/account/components/AccountHeaderUI.stories.tsx @@ -1,9 +1,12 @@ import { Button } from "@/components/ui/button"; -import { getThirdwebClient } from "@/constants/thirdweb.server"; import type { Meta, StoryObj } from "@storybook/react"; import { ThirdwebProvider } from "thirdweb/react"; import { teamsAndProjectsStub } from "../../../stories/stubs"; -import { BadgeContainer, mobileViewport } from "../../../stories/utils"; +import { + BadgeContainer, + mobileViewport, + storybookThirdwebClient, +} from "../../../stories/utils"; import { AccountHeaderDesktopUI, AccountHeaderMobileUI, @@ -37,7 +40,6 @@ export const Mobile: Story = { }, }; -const client = getThirdwebClient(); const accountAddressStub = "0x1F846F6DAE38E1C88D71EAA191760B15f38B7A37"; function Variants(props: { @@ -61,7 +63,7 @@ function Variants(props: { id: "foo", email: "foo@example.com", }} - client={client} + client={storybookThirdwebClient} getChangelogNotifications={() => Promise.resolve([])} getInboxNotifications={() => Promise.resolve([])} markNotificationAsRead={() => Promise.resolve()} diff --git a/apps/dashboard/src/app/account/components/AccountHeaderUI.tsx b/apps/dashboard/src/app/account/components/AccountHeaderUI.tsx index 4ad6d399241..edfa0c9c79b 100644 --- a/apps/dashboard/src/app/account/components/AccountHeaderUI.tsx +++ b/apps/dashboard/src/app/account/components/AccountHeaderUI.tsx @@ -117,6 +117,7 @@ export function AccountHeaderMobileUI(props: AccountHeaderCompProps) { teamsAndProjects={props.teamsAndProjects} upgradeTeamLink={undefined} account={props.account} + client={props.client} /> )}
    diff --git a/apps/dashboard/src/app/account/contracts/DeployedContractsPageHeader.tsx b/apps/dashboard/src/app/account/contracts/DeployedContractsPageHeader.tsx index 30b7cdfd90f..dc124c26fcb 100644 --- a/apps/dashboard/src/app/account/contracts/DeployedContractsPageHeader.tsx +++ b/apps/dashboard/src/app/account/contracts/DeployedContractsPageHeader.tsx @@ -52,7 +52,6 @@ export function DeployedContractsPageHeader(props: { href="/explore" category="contracts" label="deploy-contract" - target="_blank" > Deploy contract diff --git a/apps/dashboard/src/app/account/overview/AccountTeamsUI.stories.tsx b/apps/dashboard/src/app/account/overview/AccountTeamsUI.stories.tsx index 997a9b5a27f..765168d4b39 100644 --- a/apps/dashboard/src/app/account/overview/AccountTeamsUI.stories.tsx +++ b/apps/dashboard/src/app/account/overview/AccountTeamsUI.stories.tsx @@ -1,7 +1,10 @@ -import { getThirdwebClient } from "@/constants/thirdweb.server"; import type { Meta, StoryObj } from "@storybook/react"; import { teamStub } from "../../../stories/stubs"; -import { BadgeContainer, mobileViewport } from "../../../stories/utils"; +import { + BadgeContainer, + mobileViewport, + storybookThirdwebClient, +} from "../../../stories/utils"; import { AccountTeamsUI } from "./AccountTeamsUI"; const meta = { @@ -37,7 +40,7 @@ function Variants() {
    { const member = await getMemberById(team.slug, account.id); @@ -42,10 +47,7 @@ export default async function Page() {
    - +
    ); diff --git a/apps/dashboard/src/app/account/settings/AccountSettingsPageUI.stories.tsx b/apps/dashboard/src/app/account/settings/AccountSettingsPageUI.stories.tsx index ce46d76631c..1866df9c812 100644 --- a/apps/dashboard/src/app/account/settings/AccountSettingsPageUI.stories.tsx +++ b/apps/dashboard/src/app/account/settings/AccountSettingsPageUI.stories.tsx @@ -7,10 +7,12 @@ import { SelectTrigger, SelectValue, } from "@/components/ui/select"; -import { getThirdwebClient } from "@/constants/thirdweb.server"; import type { Meta, StoryObj } from "@storybook/react"; import { useState } from "react"; -import { mobileViewport } from "../../../stories/utils"; +import { + mobileViewport, + storybookThirdwebClient, +} from "../../../stories/utils"; import { AccountSettingsPageUI } from "./AccountSettingsPageUI"; const meta = { @@ -41,8 +43,6 @@ export const Mobile: Story = { }, }; -const client = getThirdwebClient(); - function Variants() { const [isVerifiedEmail, setIsVerifiedEmail] = useState(true); const [sendEmailFails, setSendEmailFails] = useState(false); @@ -119,7 +119,7 @@ function Variants() { ? new Date().toISOString() : undefined, }} - client={client} + client={storybookThirdwebClient} updateAccountAvatar={async () => { await new Promise((resolve) => setTimeout(resolve, 1000)); }} diff --git a/apps/dashboard/src/app/account/settings/page.tsx b/apps/dashboard/src/app/account/settings/page.tsx index 26d76ce7173..31486fe5cd4 100644 --- a/apps/dashboard/src/app/account/settings/page.tsx +++ b/apps/dashboard/src/app/account/settings/page.tsx @@ -18,10 +18,15 @@ export default async function Page() { loginRedirect(pagePath); } + const client = getThirdwebClient({ + jwt: token, + teamId: undefined, + }); + return ( diff --git a/apps/dashboard/src/app/api/lib/getAuthToken.ts b/apps/dashboard/src/app/api/lib/getAuthToken.ts index 6972a095d7d..6fc87f94507 100644 --- a/apps/dashboard/src/app/api/lib/getAuthToken.ts +++ b/apps/dashboard/src/app/api/lib/getAuthToken.ts @@ -1,5 +1,7 @@ import { COOKIE_ACTIVE_ACCOUNT, COOKIE_PREFIX_TOKEN } from "@/constants/cookie"; +import { getThirdwebClient } from "@/constants/thirdweb.server"; import { cookies } from "next/headers"; +import { LAST_USED_TEAM_ID } from "../../../constants/cookies"; export async function getAuthToken() { const cookiesManager = await cookies(); @@ -26,3 +28,14 @@ export async function getAuthTokenWalletAddress() { return null; } + +export async function getUserThirdwebClient() { + const authToken = await getAuthToken(); + const cookiesManager = await cookies(); + const lastUsedTeamId = cookiesManager.get(LAST_USED_TEAM_ID)?.value; + + return getThirdwebClient({ + jwt: authToken, + teamId: lastUsedTeamId, + }); +} diff --git a/apps/dashboard/src/app/drops/[slug]/opengraph-image.tsx b/apps/dashboard/src/app/drops/[slug]/opengraph-image.tsx index 5176c666b3a..58522c1eb1e 100644 --- a/apps/dashboard/src/app/drops/[slug]/opengraph-image.tsx +++ b/apps/dashboard/src/app/drops/[slug]/opengraph-image.tsx @@ -81,9 +81,10 @@ export default async function Image({ params }: { params: { slug: string } }) { ), // download the chain icon if there is one chain.icon?.url && hasWorkingChainIcon - ? download({ uri: chain.icon.url, client: getThirdwebClient() }).then( - (res) => res.arrayBuffer(), - ) + ? download({ + uri: chain.icon.url, + client: getThirdwebClient(undefined), + }).then((res) => res.arrayBuffer()) : undefined, // download the background image (based on chain) fetch( diff --git a/apps/dashboard/src/app/drops/[slug]/page.tsx b/apps/dashboard/src/app/drops/[slug]/page.tsx index 41d084d0cdd..9b569a4afd8 100644 --- a/apps/dashboard/src/app/drops/[slug]/page.tsx +++ b/apps/dashboard/src/app/drops/[slug]/page.tsx @@ -39,7 +39,7 @@ export default async function DropPage({ } // eslint-disable-next-line no-restricted-syntax const chain = defineDashboardChain(project.chainId, undefined); - const client = getThirdwebClient(); + const client = getThirdwebClient(undefined); const contract = getContract({ address: project.contractAddress, diff --git a/apps/dashboard/src/app/get-started/team/[team_slug]/layout.tsx b/apps/dashboard/src/app/get-started/team/[team_slug]/layout.tsx index fc9ed44658b..b0dbc97de12 100644 --- a/apps/dashboard/src/app/get-started/team/[team_slug]/layout.tsx +++ b/apps/dashboard/src/app/get-started/team/[team_slug]/layout.tsx @@ -2,6 +2,7 @@ import { getProjects } from "@/api/projects"; import { getTeamBySlug, getTeams } from "@/api/team"; import { AppFooter } from "@/components/blocks/app-footer"; import { notFound } from "next/navigation"; +import { getThirdwebClient } from "../../../../@/constants/thirdweb.server"; import { getValidAccount } from "../../../account/settings/getAccount"; import { getAuthToken, @@ -42,10 +43,16 @@ export default async function Layout(props: { })), ); + const client = getThirdwebClient({ + jwt: authToken, + teamId: team.id, + }); + return (
    diff --git a/apps/dashboard/src/app/nebula-app/(app)/components/Chats.stories.tsx b/apps/dashboard/src/app/nebula-app/(app)/components/Chats.stories.tsx index 5bff9807dee..3891e5c11c4 100644 --- a/apps/dashboard/src/app/nebula-app/(app)/components/Chats.stories.tsx +++ b/apps/dashboard/src/app/nebula-app/(app)/components/Chats.stories.tsx @@ -1,8 +1,10 @@ -import { getThirdwebClient } from "@/constants/thirdweb.server"; import type { Meta, StoryObj } from "@storybook/react"; import { ConnectButton, ThirdwebProvider } from "thirdweb/react"; import { randomLorem } from "../../../../stories/stubs"; -import { BadgeContainer } from "../../../../stories/utils"; +import { + BadgeContainer, + storybookThirdwebClient, +} from "../../../../stories/utils"; import { type ChatMessage, Chats } from "./Chats"; const meta = { @@ -135,7 +137,7 @@ function Story() {
    - +
    {}} - client={getThirdwebClient()} + client={storybookThirdwebClient} authToken="xxxxx" isChatStreaming={false} sessionId="xxxxx" @@ -218,7 +220,7 @@ function Story() { {}} - client={getThirdwebClient()} + client={storybookThirdwebClient} authToken="xxxxx" isChatStreaming={false} sessionId="xxxxx" @@ -249,7 +251,7 @@ function Variant(props: { {}} - client={getThirdwebClient()} + client={storybookThirdwebClient} authToken="xxxxx" isChatStreaming={false} sessionId="xxxxx" diff --git a/apps/dashboard/src/app/nebula-app/(app)/components/ExecuteTransactionCard.stories.tsx b/apps/dashboard/src/app/nebula-app/(app)/components/ExecuteTransactionCard.stories.tsx index e7e8a350f06..be534a73a53 100644 --- a/apps/dashboard/src/app/nebula-app/(app)/components/ExecuteTransactionCard.stories.tsx +++ b/apps/dashboard/src/app/nebula-app/(app)/components/ExecuteTransactionCard.stories.tsx @@ -1,8 +1,10 @@ -import { getThirdwebClient } from "@/constants/thirdweb.server"; import type { Meta, StoryObj } from "@storybook/react"; import { useState } from "react"; import { ConnectButton, ThirdwebProvider } from "thirdweb/react"; -import { BadgeContainer } from "../../../../stories/utils"; +import { + BadgeContainer, + storybookThirdwebClient, +} from "../../../../stories/utils"; import { ExecuteTransactionCardLayout, type TxStatus, @@ -25,8 +27,6 @@ export const Variants: Story = { args: {}, }; -const client = getThirdwebClient(); - const exampleTxHash = "0xbe81f5a6421625052214b41bb79d1d82751b29aa5639b54d120f00531bb8bcf"; @@ -35,7 +35,7 @@ function Story() {
    - +
    @@ -66,7 +66,7 @@ function Variant(props: { ; -const client = getThirdwebClient(); - export const LoggedIn: Story = { args: { authToken: "foo", nebulaParams: undefined, label: "Ask AI about this contract", examplePrompts: examplePrompts, - client, + client: storybookThirdwebClient, }, }; @@ -37,6 +35,6 @@ export const LoggedOut: Story = { nebulaParams: undefined, label: "Ask AI about this contract", examplePrompts: examplePrompts, - client, + client: storybookThirdwebClient, }, }; diff --git a/apps/dashboard/src/app/project-showcase/[slug]/page.tsx b/apps/dashboard/src/app/project-showcase/[slug]/page.tsx index 09a92a85e81..c130bb74636 100644 --- a/apps/dashboard/src/app/project-showcase/[slug]/page.tsx +++ b/apps/dashboard/src/app/project-showcase/[slug]/page.tsx @@ -77,7 +77,7 @@ export default async function DetailPage(props: { src={ project.image?.startsWith("ipfs://") ? (resolveSchemeWithErrorHandler({ - client: getThirdwebClient(), + client: getThirdwebClient(undefined), uri: project.image, }) ?? "") : (project.image ?? "/assets/showcase/default_image.png") diff --git a/apps/dashboard/src/app/project-showcase/page.tsx b/apps/dashboard/src/app/project-showcase/page.tsx index 63a31dbbb5c..5b88eaadd99 100644 --- a/apps/dashboard/src/app/project-showcase/page.tsx +++ b/apps/dashboard/src/app/project-showcase/page.tsx @@ -66,6 +66,8 @@ export default async function ProjectShowcasePage(props: { currentPage * PROJECT_SHOWCASE_ITEMS_PER_PAGE, ); + const client = getThirdwebClient(undefined); + return (
    @@ -137,7 +139,7 @@ export default async function ProjectShowcasePage(props: { src={ project.image?.startsWith("ipfs://") ? (resolveSchemeWithErrorHandler({ - client: getThirdwebClient(), + client, uri: project.image, }) ?? "") : (project.image ?? diff --git a/apps/dashboard/src/app/team/[team_slug]/(team)/layout.tsx b/apps/dashboard/src/app/team/[team_slug]/(team)/layout.tsx index a60e7527c04..bc1a51fc6d4 100644 --- a/apps/dashboard/src/app/team/[team_slug]/(team)/layout.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/(team)/layout.tsx @@ -2,10 +2,14 @@ import { getProjects } from "@/api/projects"; import { getTeams } from "@/api/team"; import { AppFooter } from "@/components/blocks/app-footer"; import { TabPathLinks } from "@/components/ui/tabs"; +import { getThirdwebClient } from "@/constants/thirdweb.server"; import { redirect } from "next/navigation"; import { AnnouncementBanner } from "../../../../components/notices/AnnouncementBanner"; import { getValidAccount } from "../../../account/settings/getAccount"; -import { getAuthTokenWalletAddress } from "../../../api/lib/getAuthToken"; +import { + getAuthToken, + getAuthTokenWalletAddress, +} from "../../../api/lib/getAuthToken"; import { TeamHeaderLoggedIn } from "../../components/TeamHeader/team-header-logged-in.client"; export default async function TeamLayout(props: { @@ -14,13 +18,14 @@ export default async function TeamLayout(props: { }) { const params = await props.params; - const [accountAddress, account, teams] = await Promise.all([ + const [accountAddress, account, teams, authToken] = await Promise.all([ getAuthTokenWalletAddress(), getValidAccount(`/team/${params.team_slug}`), getTeams(), + getAuthToken(), ]); - if (!teams || !accountAddress) { + if (!teams || !accountAddress || !authToken) { redirect("/login"); } @@ -39,6 +44,11 @@ export default async function TeamLayout(props: { })), ); + const client = getThirdwebClient({ + jwt: authToken, + teamId: team.id, + }); + return (
    @@ -49,6 +59,7 @@ export default async function TeamLayout(props: { currentProject={undefined} account={account} accountAddress={accountAddress} + client={client} />
    diff --git a/apps/dashboard/src/app/team/[team_slug]/(team)/~/ecosystem/create/EcosystemCreatePage.tsx b/apps/dashboard/src/app/team/[team_slug]/(team)/~/ecosystem/create/EcosystemCreatePage.tsx index d4813ff4820..55353817b9f 100644 --- a/apps/dashboard/src/app/team/[team_slug]/(team)/~/ecosystem/create/EcosystemCreatePage.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/(team)/~/ecosystem/create/EcosystemCreatePage.tsx @@ -1,12 +1,18 @@ import { CreateEcosystemForm } from "./components/client/create-ecosystem-form.client"; import { EcosystemWalletPricingCard } from "./components/pricing-card"; -export async function EcosystemCreatePage(props: { teamSlug: string }) { +export async function EcosystemCreatePage(props: { + teamSlug: string; + teamId: string; +}) { return (
    - +
    diff --git a/apps/dashboard/src/app/team/[team_slug]/(team)/~/ecosystem/create/actions/create-ecosystem.ts b/apps/dashboard/src/app/team/[team_slug]/(team)/~/ecosystem/create/actions/create-ecosystem.ts index e1ffebe2c9e..68c891e36af 100644 --- a/apps/dashboard/src/app/team/[team_slug]/(team)/~/ecosystem/create/actions/create-ecosystem.ts +++ b/apps/dashboard/src/app/team/[team_slug]/(team)/~/ecosystem/create/actions/create-ecosystem.ts @@ -8,6 +8,7 @@ import { getAuthToken } from "../../../../../../../api/lib/getAuthToken"; export async function createEcosystem(options: { teamSlug: string; + teamId: string; name: string; logo: File; permission: "PARTNER_WHITELIST" | "ANYONE"; @@ -19,10 +20,13 @@ export async function createEcosystem(options: { }; } - const { teamSlug, logo, ...data } = options; + const { teamSlug, teamId, logo, ...data } = options; const imageUrl = await upload({ - client: getThirdwebClient(token), + client: getThirdwebClient({ + jwt: token, + teamId: teamId, + }), files: [logo], }); diff --git a/apps/dashboard/src/app/team/[team_slug]/(team)/~/ecosystem/create/components/client/create-ecosystem-form.client.tsx b/apps/dashboard/src/app/team/[team_slug]/(team)/~/ecosystem/create/components/client/create-ecosystem-form.client.tsx index e5b5dee22a1..32acacae3f3 100644 --- a/apps/dashboard/src/app/team/[team_slug]/(team)/~/ecosystem/create/components/client/create-ecosystem-form.client.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/(team)/~/ecosystem/create/components/client/create-ecosystem-form.client.tsx @@ -41,7 +41,10 @@ const formSchema = z.object({ permission: z.union([z.literal("PARTNER_WHITELIST"), z.literal("ANYONE")]), }); -export function CreateEcosystemForm(props: { teamSlug: string }) { +export function CreateEcosystemForm(props: { + teamSlug: string; + teamId: string; +}) { const form = useForm>({ resolver: zodResolver(formSchema), defaultValues: { @@ -56,6 +59,7 @@ export function CreateEcosystemForm(props: { teamSlug: string }) { onSubmit={form.handleSubmit(async (values) => { const res = await createEcosystem({ teamSlug: props.teamSlug, + teamId: props.teamId, ...values, }); switch (res.status) { diff --git a/apps/dashboard/src/app/team/[team_slug]/(team)/~/ecosystem/create/page.tsx b/apps/dashboard/src/app/team/[team_slug]/(team)/~/ecosystem/create/page.tsx index 11fc8b6d1bc..0c52e6b8082 100644 --- a/apps/dashboard/src/app/team/[team_slug]/(team)/~/ecosystem/create/page.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/(team)/~/ecosystem/create/page.tsx @@ -1,8 +1,16 @@ +import { getTeamBySlug } from "@/api/team"; +import { notFound } from "next/navigation"; import { EcosystemCreatePage } from "./EcosystemCreatePage"; export default async function Page(props: { params: Promise<{ team_slug: string }>; }) { const { team_slug } = await props.params; - return ; + const team = await getTeamBySlug(team_slug); + + if (!team) { + return notFound(); + } + + return ; } diff --git a/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/general/GeneralSettingsPage.stories.tsx b/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/general/GeneralSettingsPage.stories.tsx index 57a66fdd0df..60dc0574a4c 100644 --- a/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/general/GeneralSettingsPage.stories.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/general/GeneralSettingsPage.stories.tsx @@ -1,6 +1,6 @@ -import { getThirdwebClient } from "@/constants/thirdweb.server"; import type { Meta, StoryObj } from "@storybook/react"; import { teamStub } from "../../../../../../../stories/stubs"; +import { storybookThirdwebClient } from "../../../../../../../stories/utils"; import { DeleteTeamCard, LeaveTeamCard, @@ -38,7 +38,7 @@ function Story() { console.log(value); await new Promise((resolve) => setTimeout(resolve, 1000)); }} - client={getThirdwebClient()} + client={storybookThirdwebClient} leaveTeam={async () => { await new Promise((resolve) => setTimeout(resolve, 1000)); }} diff --git a/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/general/Sidebar.stories.tsx b/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/general/Sidebar.stories.tsx index 09069c91cc2..f7c8508af61 100644 --- a/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/general/Sidebar.stories.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/general/Sidebar.stories.tsx @@ -1,9 +1,9 @@ -import { getThirdwebClient } from "@/constants/thirdweb.server"; import type { Meta, StoryObj } from "@storybook/react"; import { teamStub } from "../../../../../../../stories/stubs"; import { BadgeContainer, mobileViewport, + storybookThirdwebClient, } from "../../../../../../../stories/utils"; import { TeamSettingsSidebar } from "../_components/sidebar/TeamSettingsSidebar"; import { TeamSettingsMobileNav } from "../_components/sidebar/TeamsMobileNav"; @@ -36,8 +36,6 @@ export const Mobile: Story = { }, }; -const client = getThirdwebClient(); - function Story(props: { type: "mobile" | "desktop"; }) { @@ -51,7 +49,7 @@ function Story(props: { account={{ id: "x", }} - client={client} + client={storybookThirdwebClient} /> @@ -59,7 +57,7 @@ function Story(props: {
    diff --git a/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/members/ManageInvitesSection.stories.tsx b/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/members/ManageInvitesSection.stories.tsx index 1a9590de416..7b63e31ef36 100644 --- a/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/members/ManageInvitesSection.stories.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/members/ManageInvitesSection.stories.tsx @@ -1,9 +1,11 @@ import type { TeamInvite } from "@/api/team-invites"; import type { TeamAccountRole } from "@/api/team-members"; -import { getThirdwebClient } from "@/constants/thirdweb.server"; import type { Meta, StoryObj } from "@storybook/react"; import { teamStub } from "../../../../../../../stories/stubs"; -import { BadgeContainer } from "../../../../../../../stories/utils"; +import { + BadgeContainer, + storybookThirdwebClient, +} from "../../../../../../../stories/utils"; import { ManageInvitesSection } from "./ManageInvitesSection"; const meta = { @@ -70,7 +72,7 @@ function Story() { team={freeTeam} userHasEditPermission={true} teamInvites={invitesStub} - client={getThirdwebClient()} + client={storybookThirdwebClient} deleteInvite={deleteInviteStub} /> @@ -80,7 +82,7 @@ function Story() { team={freeTeam} userHasEditPermission={false} teamInvites={invitesStub} - client={getThirdwebClient()} + client={storybookThirdwebClient} deleteInvite={deleteInviteStub} /> diff --git a/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/members/TeamMembersSettingsPage.stories.tsx b/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/members/TeamMembersSettingsPage.stories.tsx index 2125b15383f..d8d7defa591 100644 --- a/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/members/TeamMembersSettingsPage.stories.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/members/TeamMembersSettingsPage.stories.tsx @@ -1,8 +1,10 @@ import type { TeamAccountRole, TeamMember } from "@/api/team-members"; -import { getThirdwebClient } from "@/constants/thirdweb.server"; import type { Meta, StoryObj } from "@storybook/react"; import { teamStub } from "../../../../../../../stories/stubs"; -import { BadgeContainer } from "../../../../../../../stories/utils"; +import { + BadgeContainer, + storybookThirdwebClient, +} from "../../../../../../../stories/utils"; import { ManageMembersSection } from "./ManageMembersSection"; const meta = { @@ -77,7 +79,7 @@ function Story() { team={freeTeam} userHasEditPermission={true} members={membersStub} - client={getThirdwebClient()} + client={storybookThirdwebClient} deleteMember={deleteMemberStub} /> @@ -87,7 +89,7 @@ function Story() { team={freeTeam} userHasEditPermission={false} members={membersStub} - client={getThirdwebClient()} + client={storybookThirdwebClient} deleteMember={deleteMemberStub} /> @@ -97,7 +99,7 @@ function Story() { team={freeTeam} userHasEditPermission={true} members={membersStubNoName} - client={getThirdwebClient()} + client={storybookThirdwebClient} deleteMember={deleteMemberStub} /> diff --git a/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/members/page.tsx b/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/members/page.tsx index c394777aa40..b5f06a3c9e1 100644 --- a/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/members/page.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/members/page.tsx @@ -50,12 +50,17 @@ export default async function Page(props: { (invite) => invite.status === "pending" || invite.status === "expired", ); + const client = getThirdwebClient({ + jwt: authToken, + teamId: team.id, + }); + return ( ); diff --git a/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/page.tsx b/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/page.tsx index f4a4a2f07d9..9d66c2d3cd7 100644 --- a/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/page.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/page.tsx @@ -22,10 +22,15 @@ export default async function Page(props: { notFound(); } + const client = getThirdwebClient({ + jwt: token, + teamId: team.id, + }); + return ( ); diff --git a/apps/dashboard/src/app/team/[team_slug]/(team)/~/usage/overview/components/SponsoredTransactionsTableUI.stories.tsx b/apps/dashboard/src/app/team/[team_slug]/(team)/~/usage/overview/components/SponsoredTransactionsTableUI.stories.tsx index fab4244d957..a2e0d17ef33 100644 --- a/apps/dashboard/src/app/team/[team_slug]/(team)/~/usage/overview/components/SponsoredTransactionsTableUI.stories.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/(team)/~/usage/overview/components/SponsoredTransactionsTableUI.stories.tsx @@ -1,10 +1,10 @@ import { Label } from "@/components/ui/label"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; -import { getThirdwebClient } from "@/constants/thirdweb.server"; import type { Meta, StoryObj } from "@storybook/react"; import { useState } from "react"; import { ThirdwebProvider } from "thirdweb/react"; import { projectStub } from "../../../../../../../../stories/stubs"; +import { storybookThirdwebClient } from "../../../../../../../../stories/utils"; import { type SponsoredTransaction, SponsoredTransactionsTableUI, @@ -64,8 +64,6 @@ function createSponsoredTransactionStub() { } satisfies SponsoredTransaction; } -const client = getThirdwebClient(); - export const Default: Story = { args: { totalPages: 4, @@ -157,7 +155,7 @@ function Variant(props: { filters={{}} setFilters={() => {}} isError={props.isError} - client={client} + client={storybookThirdwebClient} totalPages={props.totalPages} isPending={props.isPending} pageNumber={pageNumber} diff --git a/apps/dashboard/src/app/team/[team_slug]/(team)/~/usage/page.tsx b/apps/dashboard/src/app/team/[team_slug]/(team)/~/usage/page.tsx index 11ea58441fe..84c54d049e3 100644 --- a/apps/dashboard/src/app/team/[team_slug]/(team)/~/usage/page.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/(team)/~/usage/page.tsx @@ -56,7 +56,10 @@ export default async function Page(props: { ); } - const client = getThirdwebClient(authToken); + const client = getThirdwebClient({ + jwt: authToken, + teamId: team.id, + }); return ( { try { - localStorage.setItem(LAST_USED_PROJECT_ID, props.projectId); - localStorage.setItem(LAST_USED_TEAM_ID, props.teamId); + setCookie(LAST_USED_PROJECT_ID, props.projectId); + setCookie(LAST_USED_TEAM_ID, props.teamId); } catch { // ignore localStorage errors } diff --git a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/components/Transactions/TransactionCharts.tsx b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/components/Transactions/TransactionCharts.tsx index ac8f2cdee70..f00da815aef 100644 --- a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/components/Transactions/TransactionCharts.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/components/Transactions/TransactionCharts.tsx @@ -1,7 +1,6 @@ -import { defineChain, getContract } from "thirdweb"; +import { type ThirdwebClient, defineChain, getContract } from "thirdweb"; import { getChainMetadata } from "thirdweb/chains"; import { TransactionsChartCardUI } from "../../../(team)/_components/TransactionsCard"; -import { getThirdwebClient } from "../../../../../../@/constants/thirdweb.server"; import { fetchDashboardContractMetadata } from "../../../../../../@3rdweb-sdk/react/hooks/useDashboardContractMetadata"; import type { TransactionStats } from "../../../../../../types/analytics"; import { PieChartCard } from "../../../../components/Analytics/PieChartCard"; @@ -10,10 +9,12 @@ export function TransactionsChartsUI({ data, aggregatedData, searchParams, + client, }: { data: TransactionStats[]; aggregatedData: TransactionStats[]; searchParams: { [key: string]: string | string[] | undefined }; + client: ThirdwebClient; }) { return ( <> @@ -25,7 +26,7 @@ export function TransactionsChartsUI({ />
    - +
    ); @@ -65,7 +66,8 @@ async function ChainDistributionCard({ data }: { data: TransactionStats[] }) { async function ContractDistributionCard({ data, -}: { data: TransactionStats[] }) { + client, +}: { data: TransactionStats[]; client: ThirdwebClient }) { const _reducedData = await Promise.all( Object.entries( data @@ -97,7 +99,7 @@ async function ContractDistributionCard({ getContract({ chain, address: contractAddress as string, // we filter above - client: getThirdwebClient(), + client, }), ).catch(() => undefined); return { diff --git a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/components/Transactions/index.tsx b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/components/Transactions/index.tsx index bd6d0379ecd..002c9cd7e65 100644 --- a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/components/Transactions/index.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/components/Transactions/index.tsx @@ -1,5 +1,6 @@ import { LoadingChartState } from "components/analytics/empty-chart-state"; import { Suspense } from "react"; +import type { ThirdwebClient } from "thirdweb"; import type { AnalyticsQueryParams } from "types/analytics"; import { getClientTransactions } from "../../../../../../@/api/analytics"; import { TransactionsChartsUI } from "./TransactionCharts"; @@ -7,6 +8,7 @@ import { TransactionsChartsUI } from "./TransactionCharts"; export function TransactionsCharts( props: AnalyticsQueryParams & { searchParams: { [key: string]: string | string[] | undefined }; + client: ThirdwebClient; }, ) { return ( @@ -26,6 +28,7 @@ export function TransactionsCharts( async function TransactionsChartCardAsync( props: AnalyticsQueryParams & { searchParams: { [key: string]: string | string[] | undefined }; + client: ThirdwebClient; }, ) { const [data, aggregatedData] = await Promise.all([ @@ -45,6 +48,7 @@ async function TransactionsChartCardAsync( data={data} aggregatedData={aggregatedData} searchParams={props.searchParams} + client={props.client} /> ); } diff --git a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/account-abstraction/factories/page.tsx b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/account-abstraction/factories/page.tsx index 698b2738a62..065cda369ce 100644 --- a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/account-abstraction/factories/page.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/account-abstraction/factories/page.tsx @@ -115,7 +115,10 @@ async function AsyncYourFactories(props: { authToken: props.authToken, }); - const client = getThirdwebClient(props.authToken); + const client = getThirdwebClient({ + jwt: props.authToken, + teamId: props.teamId, + }); const factories = ( await Promise.all( diff --git a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/account-abstraction/page.tsx b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/account-abstraction/page.tsx index bb660eddb46..abc7522738b 100644 --- a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/account-abstraction/page.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/account-abstraction/page.tsx @@ -69,6 +69,11 @@ export default async function Page(props: { period: interval, }); + const client = getThirdwebClient({ + jwt: authToken, + teamId: project.teamId, + }); + return (
    ; }) { const params = await props.params; - const [accountAddress, teams, account] = await Promise.all([ + const [accountAddress, teams, account, authToken] = await Promise.all([ getAuthTokenWalletAddress(), getTeams(), getValidAccount(`/team/${params.team_slug}/${params.project_slug}`), + getAuthToken(), ]); - if (!teams || !accountAddress) { + if (!teams || !accountAddress || !authToken) { redirect("/login"); } @@ -50,6 +55,10 @@ export default async function ProjectLayout(props: { } const layoutPath = `/team/${params.team_slug}/${params.project_slug}`; + const client = getThirdwebClient({ + jwt: authToken, + teamId: team.id, + }); return ( @@ -62,6 +71,7 @@ export default async function ProjectLayout(props: { teamsAndProjects={teamsAndProjects} account={account} accountAddress={accountAddress} + client={client} />
    diff --git a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/page.tsx b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/page.tsx index 78dc7d4be97..e37650f24c3 100644 --- a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/page.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/page.tsx @@ -22,21 +22,24 @@ import { isProjectActive, } from "@/api/analytics"; import { EmptyStateCard } from "app/team/components/Analytics/EmptyStateCard"; +import { RangeSelector } from "components/analytics/range-selector"; import { Suspense } from "react"; +import type { ThirdwebClient } from "thirdweb"; import { type ChainMetadata, defineChain, getChainMetadata, } from "thirdweb/chains"; import { type WalletId, getWalletInfo } from "thirdweb/wallets"; +import { getThirdwebClient } from "../../../../@/constants/thirdweb.server"; +import { getAuthToken } from "../../../api/lib/getAuthToken"; +import { loginRedirect } from "../../../login/loginRedirect"; import { CombinedBarChartCard } from "../../components/Analytics/CombinedBarChartCard"; import { PieChartCard } from "../../components/Analytics/PieChartCard"; import { ProjectFTUX } from "./components/ProjectFTUX/ProjectFTUX"; import { RpcMethodBarChartCard } from "./components/RpcMethodBarChartCard"; import { TransactionsCharts } from "./components/Transactions"; -import { RangeSelector } from "components/analytics/range-selector"; - interface PageParams { team_slug: string; project_slug: string; @@ -57,7 +60,14 @@ export default async function ProjectOverviewPage(props: PageProps) { props.searchParams, ]); - const project = await getProject(params.team_slug, params.project_slug); + const [authToken, project] = await Promise.all([ + getAuthToken(), + getProject(params.team_slug, params.project_slug), + ]); + + if (!authToken) { + loginRedirect(`/team/${params.team_slug}`); + } if (!project) { redirect(`/team/${params.team_slug}`); @@ -78,6 +88,11 @@ export default async function ProjectOverviewPage(props: PageProps) { const isActive = Object.values(activeStatus).some((v) => !!v); + const client = getThirdwebClient({ + jwt: authToken, + teamId: project.teamId, + }); + return (
    @@ -105,6 +120,7 @@ export default async function ProjectOverviewPage(props: PageProps) { range={range} interval={interval} searchParams={searchParams} + client={client} />
    @@ -120,8 +136,9 @@ async function ProjectAnalytics(props: { range: Range; interval: "day" | "week"; searchParams: PageSearchParams; + client: ThirdwebClient; }) { - const { project, range, interval, searchParams } = props; + const { project, range, interval, searchParams, client } = props; // Fetch all analytics data in parallel const [ @@ -221,6 +238,7 @@ async function ProjectAnalytics(props: { to={range.to} period={interval} teamId={project.teamId} + client={client} /> {userOpUsageTimeSeries.status === "fulfilled" && userOpUsage.status === "fulfilled" && diff --git a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/settings/ProjectGeneralSettingsPage.stories.tsx b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/settings/ProjectGeneralSettingsPage.stories.tsx index 11e36cb09d4..9304ae7158f 100644 --- a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/settings/ProjectGeneralSettingsPage.stories.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/settings/ProjectGeneralSettingsPage.stories.tsx @@ -1,6 +1,6 @@ -import { getThirdwebClient } from "@/constants/thirdweb.server"; import type { Meta, StoryObj } from "@storybook/react"; import { projectStub, teamStub } from "../../../../../stories/stubs"; +import { storybookThirdwebClient } from "../../../../../stories/utils"; import { ProjectGeneralSettingsPageUI } from "./ProjectGeneralSettingsPage"; const meta = { @@ -44,7 +44,7 @@ function Story(props: { await new Promise((resolve) => setTimeout(resolve, 1000)); console.log("transferProject", newTeam); }} - client={getThirdwebClient()} + client={storybookThirdwebClient} teamsWithRole={[ { role: props.isOwnerAccount ? "OWNER" : "MEMBER", diff --git a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/settings/page.tsx b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/settings/page.tsx index 744075c97ac..0d42146d2d6 100644 --- a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/settings/page.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/settings/page.tsx @@ -50,6 +50,11 @@ export default async function Page(props: { }), ); + const client = getThirdwebClient({ + jwt: authToken, + teamId: currentTeam.id, + }); + const currentTeamWithRole = teamsWithRole.find( (teamWithRole) => teamWithRole.team.id === currentTeam.id, ); @@ -61,7 +66,7 @@ export default async function Page(props: { project={project} teamSlug={team_slug} showNebulaSettings={currentTeam.enabledScopes.includes("nebula")} - client={getThirdwebClient(authToken)} + client={client} teamId={currentTeam.id} teamsWithRole={teamsWithRole} isOwnerAccount={isOwnerAccount} diff --git a/apps/dashboard/src/app/team/[team_slug]/layout.tsx b/apps/dashboard/src/app/team/[team_slug]/layout.tsx index 16577a91c50..df8e0a9f3b6 100644 --- a/apps/dashboard/src/app/team/[team_slug]/layout.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/layout.tsx @@ -40,7 +40,7 @@ export default async function RootTeamLayout(props: { {props.children}
    - + diff --git a/apps/dashboard/src/app/team/components/TeamHeader/TeamHeaderUI.stories.tsx b/apps/dashboard/src/app/team/components/TeamHeader/TeamHeaderUI.stories.tsx index 0e33470299a..0cc14c2a4ca 100644 --- a/apps/dashboard/src/app/team/components/TeamHeader/TeamHeaderUI.stories.tsx +++ b/apps/dashboard/src/app/team/components/TeamHeader/TeamHeaderUI.stories.tsx @@ -1,11 +1,14 @@ import type { Project } from "@/api/projects"; import type { Team } from "@/api/team"; import { Button } from "@/components/ui/button"; -import { getThirdwebClient } from "@/constants/thirdweb.server"; import type { Meta, StoryObj } from "@storybook/react"; import { ThirdwebProvider } from "thirdweb/react"; import { teamsAndProjectsStub } from "../../../../stories/stubs"; -import { BadgeContainer, mobileViewport } from "../../../../stories/utils"; +import { + BadgeContainer, + mobileViewport, + storybookThirdwebClient, +} from "../../../../stories/utils"; import { TeamHeaderDesktopUI, TeamHeaderMobileUI } from "./TeamHeaderUI"; const meta = { @@ -36,8 +39,6 @@ export const Mobile: Story = { }, }; -const client = getThirdwebClient(); - function Variants(props: { type: "mobile" | "desktop"; }) { @@ -164,7 +165,7 @@ function Variant(props: { logout={() => {}} connectButton={} createProject={() => {}} - client={client} + client={storybookThirdwebClient} getChangelogNotifications={getChangelogsStub} getInboxNotifications={getInboxNotificationsStub} markNotificationAsRead={markNotificationAsReadStub} diff --git a/apps/dashboard/src/app/team/components/TeamHeader/TeamHeaderUI.tsx b/apps/dashboard/src/app/team/components/TeamHeader/TeamHeaderUI.tsx index 57650caf0d4..b38b9bc8aba 100644 --- a/apps/dashboard/src/app/team/components/TeamHeader/TeamHeaderUI.tsx +++ b/apps/dashboard/src/app/team/components/TeamHeader/TeamHeaderUI.tsx @@ -165,6 +165,7 @@ export function TeamHeaderMobileUI(props: TeamHeaderCompProps) { teamsAndProjects={props.teamsAndProjects} upgradeTeamLink={`/team/${currentTeam.slug}/settings`} account={props.account} + client={props.client} />
    diff --git a/apps/dashboard/src/app/team/components/TeamHeader/TeamSelectorMobileMenuButton.tsx b/apps/dashboard/src/app/team/components/TeamHeader/TeamSelectorMobileMenuButton.tsx index a94849ed37b..db8431e763a 100644 --- a/apps/dashboard/src/app/team/components/TeamHeader/TeamSelectorMobileMenuButton.tsx +++ b/apps/dashboard/src/app/team/components/TeamHeader/TeamSelectorMobileMenuButton.tsx @@ -5,9 +5,9 @@ import type { Team } from "@/api/team"; import { DynamicHeight } from "@/components/ui/DynamicHeight"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog"; -import { getThirdwebClient } from "@/constants/thirdweb.server"; import type { Account } from "@3rdweb-sdk/react/hooks/useApi"; import { ChevronsUpDownIcon } from "lucide-react"; +import type { ThirdwebClient } from "thirdweb"; import { TeamSelectionUI } from "./TeamSelectionUI"; type TeamSelectorMobileMenuButtonProps = { @@ -15,10 +15,9 @@ type TeamSelectorMobileMenuButtonProps = { teamsAndProjects: Array<{ team: Team; projects: Project[] }>; upgradeTeamLink: string | undefined; account: Pick | undefined; + client: ThirdwebClient; }; -const client = getThirdwebClient(); - export function TeamSelectorMobileMenuButton( props: TeamSelectorMobileMenuButtonProps, ) { @@ -49,7 +48,7 @@ export function TeamSelectorMobileMenuButton( teamsAndProjects={teamsAndProjects} upgradeTeamLink={props.upgradeTeamLink} account={props.account} - client={client} + client={props.client} /> diff --git a/apps/dashboard/src/app/team/components/TeamHeader/team-header-logged-in.client.tsx b/apps/dashboard/src/app/team/components/TeamHeader/team-header-logged-in.client.tsx index 24472c44080..8ab5776f172 100644 --- a/apps/dashboard/src/app/team/components/TeamHeader/team-header-logged-in.client.tsx +++ b/apps/dashboard/src/app/team/components/TeamHeader/team-header-logged-in.client.tsx @@ -2,11 +2,11 @@ import type { Project } from "@/api/projects"; import type { Team } from "@/api/team"; -import { getThirdwebClient } from "@/constants/thirdweb.server"; import { useDashboardRouter } from "@/lib/DashboardRouter"; import { CustomConnectWallet } from "@3rdweb-sdk/react/components/connect-wallet"; import type { Account } from "@3rdweb-sdk/react/hooks/useApi"; import { useCallback, useState } from "react"; +import type { ThirdwebClient } from "thirdweb"; import { useActiveWallet, useDisconnect } from "thirdweb/react"; import { LazyCreateProjectDialog } from "../../../../components/settings/ApiKeys/Create/LazyCreateAPIKeyDialog"; import { doLogout } from "../../../login/auth-actions"; @@ -27,6 +27,7 @@ export function TeamHeaderLoggedIn(props: { currentProject: Project | undefined; account: Pick; accountAddress: string; + client: ThirdwebClient; }) { const [createProjectDialogState, setCreateProjectDialogState] = useState< { team: Team; isOpen: true } | { isOpen: false } @@ -61,7 +62,7 @@ export function TeamHeaderLoggedIn(props: { team, }); }, - client: getThirdwebClient(), + client: props.client, accountAddress: props.accountAddress, getChangelogNotifications: getChangelogNotifications, getInboxNotifications: getInboxNotifications, diff --git a/apps/dashboard/src/app/team/components/TeamHeader/team-header.tsx b/apps/dashboard/src/app/team/components/TeamHeader/team-header.tsx index 08b6b42a978..e9dd3cfbad1 100644 --- a/apps/dashboard/src/app/team/components/TeamHeader/team-header.tsx +++ b/apps/dashboard/src/app/team/components/TeamHeader/team-header.tsx @@ -1,21 +1,32 @@ import { getProjects } from "@/api/projects"; import { getTeams } from "@/api/team"; +import { cookies } from "next/headers"; +import { getThirdwebClient } from "../../../../@/constants/thirdweb.server"; +import { LAST_USED_TEAM_ID } from "../../../../constants/cookies"; import { getRawAccount } from "../../../account/settings/getAccount"; -import { getAuthTokenWalletAddress } from "../../../api/lib/getAuthToken"; +import { + getAuthToken, + getAuthTokenWalletAddress, +} from "../../../api/lib/getAuthToken"; import { HeaderLoggedOut } from "../HeaderLoggedOut/HeaderLoggedOut"; import { TeamHeaderLoggedIn } from "./team-header-logged-in.client"; export async function TeamHeader() { - const [account, teams, accountAddress] = await Promise.all([ + const [account, teams, accountAddress, authToken] = await Promise.all([ getRawAccount(), getTeams(), getAuthTokenWalletAddress(), + getAuthToken(), ]); if (!account || !accountAddress || !teams) { return ; } + const cookiesObj = await cookies(); + const lastUsedTeamId = cookiesObj.get(LAST_USED_TEAM_ID)?.value; + const lastUsedTeam = teams.find((team) => team.id === lastUsedTeamId); + const teamsAndProjects = await Promise.all( teams.map(async (team) => ({ team, @@ -24,13 +35,21 @@ export async function TeamHeader() { ); const firstTeam = teams[0]; - if (!firstTeam) { + const selectedTeam = lastUsedTeam || firstTeam; + + if (!selectedTeam) { return ; } + const client = getThirdwebClient({ + jwt: authToken, + teamId: lastUsedTeam?.id, + }); + return ( { setCookie(LAST_VISITED_TEAM_PAGE_PATH, pathname); - }, [pathname]); + setCookie(LAST_USED_TEAM_ID, props.teamId); + }, [pathname, props.teamId]); return null; } diff --git a/apps/dashboard/src/components/buttons/TransactionButton.stories.tsx b/apps/dashboard/src/components/buttons/TransactionButton.stories.tsx index de62eb1d7d1..e7061d8ba53 100644 --- a/apps/dashboard/src/components/buttons/TransactionButton.stories.tsx +++ b/apps/dashboard/src/components/buttons/TransactionButton.stories.tsx @@ -8,13 +8,12 @@ import { SelectValue, } from "@/components/ui/select"; import { Switch } from "@/components/ui/switch"; -import { getThirdwebClient } from "@/constants/thirdweb.server"; import type { Meta, StoryObj } from "@storybook/react"; import { useMutation } from "@tanstack/react-query"; import { StarIcon } from "lucide-react"; import { useState } from "react"; import { ConnectButton, ThirdwebProvider } from "thirdweb/react"; -import { BadgeContainer } from "../../stories/utils"; +import { BadgeContainer, storybookThirdwebClient } from "../../stories/utils"; import { TransactionButton } from "./TransactionButton"; const meta = { @@ -79,7 +78,7 @@ function Story() {
    - +
    = ({ prefillSlug, prefillChainId, }) => { + const client = useThirdwebClient(); const { idToChain, nameToChain } = useAllChainsData(); const chainOverrides = useStore(chainOverridesStore); @@ -67,7 +69,11 @@ export const ConfigureNetworkForm: React.FC = ({ : // if chain is custom or modified, show the rpc as is editingChain.isCustom || editingChain.isModified ? editingChain.rpc[0] - : getDashboardChainRpc(editingChain.chainId, editingChain)) || "", + : getDashboardChainRpc( + editingChain.chainId, + editingChain, + client, + )) || "", chainId: editingChain?.chainId ? `${editingChain?.chainId}` : prefillChainId || "", diff --git a/apps/dashboard/src/components/contract-components/contract-deploy-form/add-to-project-card.stories.tsx b/apps/dashboard/src/components/contract-components/contract-deploy-form/add-to-project-card.stories.tsx index a3cd330fd5b..563ba08f1a3 100644 --- a/apps/dashboard/src/components/contract-components/contract-deploy-form/add-to-project-card.stories.tsx +++ b/apps/dashboard/src/components/contract-components/contract-deploy-form/add-to-project-card.stories.tsx @@ -1,7 +1,9 @@ -import { getThirdwebClient } from "@/constants/thirdweb.server"; import type { Meta, StoryObj } from "@storybook/react"; import { useState } from "react"; -import { BadgeContainer } from "../../../stories/utils"; +import { + BadgeContainer, + storybookThirdwebClient, +} from "../../../stories/utils"; import { AddToProjectCardUI, type MinimalProject, @@ -83,7 +85,7 @@ function Variant(props: { = ({ }; try { - const lastUsedTeamSlug = localStorage.getItem(LAST_USED_TEAM_ID); - const lastUsedProjectSlug = localStorage.getItem(LAST_USED_PROJECT_ID); + const lastUsedTeamSlug = getCookie(LAST_USED_TEAM_ID); + const lastUsedProjectSlug = getCookie(LAST_USED_PROJECT_ID); if (!lastUsedTeamSlug || !lastUsedProjectSlug) { return defaultSelection; diff --git a/apps/dashboard/src/components/contract-components/contract-publish-form/index.tsx b/apps/dashboard/src/components/contract-components/contract-publish-form/index.tsx index 9dc0c63ef4f..3073722c194 100644 --- a/apps/dashboard/src/components/contract-components/contract-publish-form/index.tsx +++ b/apps/dashboard/src/components/contract-components/contract-publish-form/index.tsx @@ -1,5 +1,4 @@ "use client"; -import { getThirdwebClient } from "@/constants/thirdweb.server"; import { useDashboardRouter } from "@/lib/DashboardRouter"; import { useIsomorphicLayoutEffect } from "@/lib/useIsomorphicLayoutEffect"; import { CustomConnectWallet } from "@3rdweb-sdk/react/components/connect-wallet"; @@ -21,6 +20,7 @@ import { } from "thirdweb/extensions/thirdweb"; import { useActiveAccount, useSendAndConfirmTransaction } from "thirdweb/react"; import { Button, Text } from "tw-components"; +import { useThirdwebClient } from "../../../@/constants/thirdweb.client"; import { useEns, useFunctionParamsFromABI } from "../hooks"; import { ContractParamsFieldset } from "./contract-params-fieldset"; import { FactoryFieldset } from "./factory-fieldset"; @@ -33,7 +33,7 @@ export function ContractPublishForm(props: { onPublishSuccess: () => Promise; jwt: string; }) { - const client = getThirdwebClient(props.jwt); + const client = useThirdwebClient(props.jwt); const [customFactoryAbi, setCustomFactoryAbi] = useState([]); const [fieldsetToShow, setFieldsetToShow] = useState< "landing" | "factory" | "contractParams" | "implParams" | "networks" diff --git a/apps/dashboard/src/components/contract-components/contract-publish-form/landing-fieldset.tsx b/apps/dashboard/src/components/contract-components/contract-publish-form/landing-fieldset.tsx index 0dcb4facf94..7a7408608cc 100644 --- a/apps/dashboard/src/components/contract-components/contract-publish-form/landing-fieldset.tsx +++ b/apps/dashboard/src/components/contract-components/contract-publish-form/landing-fieldset.tsx @@ -28,6 +28,7 @@ import { Link, Text, } from "tw-components"; +import { useThirdwebClient } from "../../../@/constants/thirdweb.client"; import { MarkdownRenderer } from "../published-contract/markdown-renderer"; import { ExternalLinksFieldset } from "./external-links-fieldset"; @@ -40,6 +41,7 @@ export const LandingFieldset: React.FC = ({ latestVersion, placeholderVersion, }) => { + const client = useThirdwebClient(); const form = useFormContext(); const logoUrl = useImageFileOrUrl(form.watch("logo")); @@ -103,7 +105,7 @@ export const LandingFieldset: React.FC = ({ alt="" w="100%" h="100%" - src={replaceIpfsUrl(fileUrl)} + src={replaceIpfsUrl(fileUrl, client)} borderRadius="full" /> )} diff --git a/apps/dashboard/src/components/contract-components/contract-table/index.tsx b/apps/dashboard/src/components/contract-components/contract-table/index.tsx index 5190091d671..82e7cc085c9 100644 --- a/apps/dashboard/src/components/contract-components/contract-table/index.tsx +++ b/apps/dashboard/src/components/contract-components/contract-table/index.tsx @@ -8,21 +8,23 @@ import { TableRow, } from "@/components/ui/table"; import Link from "next/link"; +import type { ThirdwebClient } from "thirdweb"; import { fetchDeployMetadata } from "../fetchDeployMetadata"; import { ContractIdImage } from "../shared/contract-id-image"; type DeployableContractTableProps = { contractIds: string[]; context: "deploy" | "publish"; + client: ThirdwebClient; }; export async function DeployableContractTable( props: DeployableContractTableProps, ) { - const { contractIds, context } = props; + const { contractIds, context, client } = props; const deployedContractMetadata = await Promise.all( contractIds.map(async (id) => { - const res = await fetchDeployMetadata(id); + const res = await fetchDeployMetadata(id, client); return { contractId: id, ...res, @@ -61,7 +63,10 @@ export async function DeployableContractTable( > {/* Icon */} - + {/* name */} diff --git a/apps/dashboard/src/components/contract-components/fetch-contracts-with-versions.ts b/apps/dashboard/src/components/contract-components/fetch-contracts-with-versions.ts index b0797f01da5..362320d4f8d 100644 --- a/apps/dashboard/src/components/contract-components/fetch-contracts-with-versions.ts +++ b/apps/dashboard/src/components/contract-components/fetch-contracts-with-versions.ts @@ -1,4 +1,3 @@ -import { getThirdwebClient } from "@/constants/thirdweb.server"; import { type ThirdwebClient, isAddress } from "thirdweb"; import { fetchDeployMetadata } from "thirdweb/contract"; import { resolveAddress } from "thirdweb/extensions/ens"; @@ -18,8 +17,8 @@ export function mapThirdwebPublisher(publisher: string) { export async function fetchPublishedContractVersions( publisherAddress: string, contractId: string, + client: ThirdwebClient, ) { - const client = getThirdwebClient(); const sortedVersions = await getSortedPublishedContractVersions({ publisherAddress, contractId, @@ -80,9 +79,8 @@ async function getSortedPublishedContractVersions(params: { export async function fetchLatestPublishedContractVersion( publisherAddress: string, contractId: string, + client: ThirdwebClient, ) { - const client = getThirdwebClient(); - const sortedVersions = await getSortedPublishedContractVersions({ publisherAddress, contractId, @@ -104,12 +102,14 @@ export async function fetchLatestPublishedContractVersion( export async function fetchPublishedContractVersion( publisherAddress: string, contractId: string, + client: ThirdwebClient, version = "latest", ) { if (version === "latest") { const latestVersion = await fetchLatestPublishedContractVersion( publisherAddress, contractId, + client, ); return latestVersion || null; @@ -118,6 +118,7 @@ export async function fetchPublishedContractVersion( const allVersions = await fetchPublishedContractVersions( publisherAddress, contractId, + client, ); if (allVersions.length === 0) { diff --git a/apps/dashboard/src/components/contract-components/fetchDeployMetadata.ts b/apps/dashboard/src/components/contract-components/fetchDeployMetadata.ts index c2a0971495c..a31f3136b69 100644 --- a/apps/dashboard/src/components/contract-components/fetchDeployMetadata.ts +++ b/apps/dashboard/src/components/contract-components/fetchDeployMetadata.ts @@ -1,16 +1,19 @@ -import { getThirdwebClient } from "@/constants/thirdweb.server"; +import type { ThirdwebClient } from "thirdweb"; import { fetchDeployMetadata as sdkFetchDeployMetadata } from "thirdweb/contract"; import { removeUndefinedFromObjectDeep } from "../../utils/object"; import type { ContractId } from "./types"; // metadata PRE publish, only has the compiler output info (from CLI) -export async function fetchDeployMetadata(contractId: string) { +export async function fetchDeployMetadata( + contractId: string, + client: ThirdwebClient, +) { const contractIdIpfsHash = toContractIdIpfsHash(contractId); return removeUndefinedFromObjectDeep( await sdkFetchDeployMetadata({ - client: getThirdwebClient(), + client, uri: contractIdIpfsHash, }), ); diff --git a/apps/dashboard/src/components/contract-components/fetchPublishedContracts.ts b/apps/dashboard/src/components/contract-components/fetchPublishedContracts.ts index a8c199c3db7..60b0f8e5155 100644 --- a/apps/dashboard/src/components/contract-components/fetchPublishedContracts.ts +++ b/apps/dashboard/src/components/contract-components/fetchPublishedContracts.ts @@ -1,5 +1,5 @@ -import { getThirdwebClient } from "@/constants/thirdweb.server"; import { resolveEns } from "lib/ens"; +import type { ThirdwebClient } from "thirdweb"; import { getAllPublishedContracts, getContractPublisher, @@ -7,12 +7,16 @@ import { import { fetchDeployMetadata } from "./fetchDeployMetadata"; // TODO: clean this up, jesus -export async function fetchPublishedContracts(address?: string | null) { +export async function fetchPublishedContracts(params: { + address?: string | null; + client: ThirdwebClient; +}) { + const { address, client } = params; try { if (!address) { return []; } - const resolvedAddress = (await resolveEns(address)).address; + const resolvedAddress = (await resolveEns(address, client)).address; if (!resolvedAddress) { return []; @@ -20,7 +24,7 @@ export async function fetchPublishedContracts(address?: string | null) { const tempResult = ( (await getAllPublishedContracts({ - contract: getContractPublisher(getThirdwebClient()), + contract: getContractPublisher(client), publisher: resolvedAddress, })) || [] ) @@ -30,7 +34,7 @@ export async function fetchPublishedContracts(address?: string | null) { return await Promise.all( tempResult.map(async (c) => ({ ...c, - metadata: await fetchDeployMetadata(c.publishMetadataUri), + metadata: await fetchDeployMetadata(c.publishMetadataUri, client), })), ); } catch (e) { diff --git a/apps/dashboard/src/components/contract-components/fetchPublishedContractsFromDeploy.ts b/apps/dashboard/src/components/contract-components/fetchPublishedContractsFromDeploy.ts index 0c54c29b90e..2cd3e9056cf 100644 --- a/apps/dashboard/src/components/contract-components/fetchPublishedContractsFromDeploy.ts +++ b/apps/dashboard/src/components/contract-components/fetchPublishedContractsFromDeploy.ts @@ -22,5 +22,7 @@ export async function fetchPublishedContractsFromDeploy(options: { compilerMetadataUri: contractUri, }); - return await Promise.all(publishURIs.map((uri) => fetchDeployMetadata(uri))); + return await Promise.all( + publishURIs.map((uri) => fetchDeployMetadata(uri, client)), + ); } diff --git a/apps/dashboard/src/components/contract-components/hooks.ts b/apps/dashboard/src/components/contract-components/hooks.ts index e514eea8517..33f808bee20 100644 --- a/apps/dashboard/src/components/contract-components/hooks.ts +++ b/apps/dashboard/src/components/contract-components/hooks.ts @@ -6,7 +6,7 @@ import type { Abi } from "abitype"; import { resolveEns } from "lib/ens"; import { useV5DashboardChain } from "lib/v5-adapter"; import { useMemo } from "react"; -import type { ThirdwebContract } from "thirdweb"; +import type { ThirdwebClient, ThirdwebContract } from "thirdweb"; import { getContract, resolveContractAbi } from "thirdweb/contract"; import { isAddress, isValidENSName } from "thirdweb/utils"; import { @@ -20,6 +20,7 @@ export function useAllVersions( publisherAddress: string | undefined, contractId: string | undefined, ) { + const client = useThirdwebClient(); return useQuery({ queryKey: ["all-releases", publisherAddress, contractId], queryFn: () => { @@ -27,7 +28,11 @@ export function useAllVersions( // should never happen because we check for this in the enabled check throw new Error("publisherAddress or contractId is not defined"); } - return fetchPublishedContractVersions(publisherAddress, contractId); + return fetchPublishedContractVersions( + publisherAddress, + contractId, + client, + ); }, enabled: !!publisherAddress && !!contractId, @@ -104,17 +109,22 @@ export type PublishedContractDetails = Awaited< >[number]; export function usePublishedContractsQuery(address?: string) { + const client = useThirdwebClient(); return useQuery({ queryKey: ["published-contracts", address], - queryFn: () => fetchPublishedContracts(address), + queryFn: () => fetchPublishedContracts({ address, client }), enabled: !!address, }); } -function ensQuery(addressOrEnsName?: string) { +function ensQuery(params: { + addressOrEnsName?: string; + client: ThirdwebClient; +}) { + let addressOrEnsName = params.addressOrEnsName; + // if the address is `thirdweb.eth` we actually want `deployer.thirdweb.eth` here... if (addressOrEnsName === "thirdweb.eth") { - // biome-ignore lint/style/noParameterAssign: FIXME addressOrEnsName = "deployer.thirdweb.eth"; } const placeholderData = { @@ -134,14 +144,15 @@ function ensQuery(addressOrEnsName?: string) { throw new Error("Invalid address or ENS name."); } - const { address, ensName } = await resolveEns(addressOrEnsName).catch( - () => ({ - address: isAddress(addressOrEnsName || "") - ? addressOrEnsName || null - : null, - ensName: null, - }), - ); + const { address, ensName } = await resolveEns( + addressOrEnsName, + params.client, + ).catch(() => ({ + address: isAddress(addressOrEnsName || "") + ? addressOrEnsName || null + : null, + ensName: null, + })); if (isValidENSName(addressOrEnsName) && !address) { throw new Error("Failed to resolve ENS name."); @@ -166,7 +177,8 @@ function ensQuery(addressOrEnsName?: string) { } export function useEns(addressOrEnsName?: string) { - return useQuery(ensQuery(addressOrEnsName)); + const client = useThirdwebClient(); + return useQuery(ensQuery({ addressOrEnsName, client })); } export function useContractEvents(abi: Abi) { diff --git a/apps/dashboard/src/components/contract-components/published-contract/index.tsx b/apps/dashboard/src/components/contract-components/published-contract/index.tsx index ea87c95b616..a4d328bc261 100644 --- a/apps/dashboard/src/components/contract-components/published-contract/index.tsx +++ b/apps/dashboard/src/components/contract-components/published-contract/index.tsx @@ -191,7 +191,10 @@ export const PublishedContract: React.FC = ({ diff --git a/apps/dashboard/src/components/contract-components/shared/contract-id-image.tsx b/apps/dashboard/src/components/contract-components/shared/contract-id-image.tsx index 1ce8303ee6f..840bb3798dc 100644 --- a/apps/dashboard/src/components/contract-components/shared/contract-id-image.tsx +++ b/apps/dashboard/src/components/contract-components/shared/contract-id-image.tsx @@ -2,15 +2,18 @@ import { replaceIpfsUrl } from "lib/sdk"; import type { StaticImageData } from "next/image"; import Image from "next/image"; +import type { ThirdwebClient } from "thirdweb"; import type { FetchDeployMetadataResult } from "thirdweb/contract"; import generalContractIcon from "../../../../public/assets/tw-icons/general.png"; type ContractIdImageProps = { deployedMetadataResult: FetchDeployMetadataResult; + client: ThirdwebClient; }; export const ContractIdImage: React.FC = ({ deployedMetadataResult, + client, }) => { const logo = deployedMetadataResult.logo; @@ -21,7 +24,11 @@ export const ContractIdImage: React.FC = ({ if (logo) { return ( - + ); } diff --git a/apps/dashboard/src/components/contract-functions/interactive-abi-function.tsx b/apps/dashboard/src/components/contract-functions/interactive-abi-function.tsx index ff5fe4be965..a8ade90f858 100644 --- a/apps/dashboard/src/components/contract-functions/interactive-abi-function.tsx +++ b/apps/dashboard/src/components/contract-functions/interactive-abi-function.tsx @@ -481,7 +481,10 @@ export const InteractiveAbiFunction: React.FC = ( formattedResponseData.data.startsWith("ipfs://") && ( null); diff --git a/apps/dashboard/src/components/explore/contract-row/index.tsx b/apps/dashboard/src/components/explore/contract-row/index.tsx index 876248c01ff..0c62ac43add 100644 --- a/apps/dashboard/src/components/explore/contract-row/index.tsx +++ b/apps/dashboard/src/components/explore/contract-row/index.tsx @@ -2,13 +2,15 @@ import type { ExploreCategory } from "data/explore"; import { ArrowRightIcon } from "lucide-react"; import Link from "next/link"; import { Suspense } from "react"; +import type { ThirdwebClient } from "thirdweb"; import { ContractCard, ContractCardSkeleton } from "../contract-card"; interface ContractRowProps { category: ExploreCategory; + client: ThirdwebClient; } -export function ContractRow({ category }: ContractRowProps) { +export function ContractRow({ category, client }: ContractRowProps) { return (
    {/* Title, Description + View all link */} @@ -75,6 +77,7 @@ export function ContractRow({ category }: ContractRowProps) { fallback={} > { - const src = ipfsSrc ? replaceIpfsUrl(ipfsSrc) : fallbackChainIcon; + const client = useThirdwebClient(); + const src = ipfsSrc ? replaceIpfsUrl(ipfsSrc, client) : fallbackChainIcon; return ( = z .custom((ens) => typeof ens === "string" && isValidENSName(ens)) - .transform(async (ens) => (await resolveEns(ens)).address) + // TODO - move this schema inside component to use client with authToken, teamId filled in + .transform( + async (ens) => + (await resolveEns(ens, getThirdwebClient(undefined))).address, + ) .refine( (address): address is `0x${string}` => !!address && isAddress(address), { diff --git a/apps/dashboard/src/core-ui/batch-upload/batch-table.tsx b/apps/dashboard/src/core-ui/batch-upload/batch-table.tsx index a9c75bca356..7116b09cf6c 100644 --- a/apps/dashboard/src/core-ui/batch-upload/batch-table.tsx +++ b/apps/dashboard/src/core-ui/batch-upload/batch-table.tsx @@ -28,11 +28,13 @@ import { import { useMemo } from "react"; import { type Column, usePagination, useTable } from "react-table"; import type { NFTInput } from "thirdweb/utils"; +import { useThirdwebClient } from "../../@/constants/thirdweb.client"; const FileImage: React.FC = ({ src, ...props }) => { + const client = useThirdwebClient(); const img = useImageFileOrUrl( typeof src === "string" && src.startsWith("ipfs://") - ? replaceIpfsUrl(src) + ? replaceIpfsUrl(src, client) : src, ); return ; @@ -41,9 +43,10 @@ const FileImage: React.FC = ({ src, ...props }) => { const FileVideo: React.FC< BoxProps & Omit, "ref"> > = ({ src, ...props }) => { + const client = useThirdwebClient(); const video = useImageFileOrUrl( typeof src === "string" && src.startsWith("ipfs://") - ? replaceIpfsUrl(src) + ? replaceIpfsUrl(src, client) : src, ); return ; diff --git a/apps/dashboard/src/lib/ens.ts b/apps/dashboard/src/lib/ens.ts index a55c67964f7..a01d8b4b74b 100644 --- a/apps/dashboard/src/lib/ens.ts +++ b/apps/dashboard/src/lib/ens.ts @@ -1,5 +1,4 @@ -import { getThirdwebClient } from "@/constants/thirdweb.server"; -import { isAddress } from "thirdweb"; +import { type ThirdwebClient, isAddress } from "thirdweb"; import { resolveAddress, resolveName } from "thirdweb/extensions/ens"; import { isValidENSName } from "thirdweb/utils"; @@ -10,12 +9,13 @@ interface ENSResolveResult { export async function resolveEns( ensNameOrAddress: string, + client: ThirdwebClient, ): Promise { if (isAddress(ensNameOrAddress)) { return { address: ensNameOrAddress, ensName: await resolveName({ - client: getThirdwebClient(), + client, address: ensNameOrAddress, }), }; @@ -26,7 +26,7 @@ export async function resolveEns( } const address = await resolveAddress({ - client: getThirdwebClient(), + client, name: ensNameOrAddress, }); diff --git a/apps/dashboard/src/lib/rpc.ts b/apps/dashboard/src/lib/rpc.ts index 1165556a44f..9a7fb4900fc 100644 --- a/apps/dashboard/src/lib/rpc.ts +++ b/apps/dashboard/src/lib/rpc.ts @@ -1,18 +1,19 @@ import { isProd } from "@/constants/env"; -import { getThirdwebClient } from "@/constants/thirdweb.server"; import { defineDashboardChain } from "lib/defineDashboardChain"; +import type { ThirdwebClient } from "thirdweb"; import { type ChainMetadata, getRpcUrlForChain } from "thirdweb/chains"; import { hostnameEndsWith } from "../utils/url"; export function getDashboardChainRpc( chainId: number, dashboardChain: ChainMetadata | undefined, + client: ThirdwebClient, ) { try { const rpcUrl = getRpcUrlForChain({ // eslint-disable-next-line no-restricted-syntax chain: defineDashboardChain(chainId, dashboardChain), - client: getThirdwebClient(), + client, }); // based on the environment hit dev or production if (hostnameEndsWith(rpcUrl, "rpc.thirdweb.com")) { diff --git a/apps/dashboard/src/lib/sdk.ts b/apps/dashboard/src/lib/sdk.ts index 54c8f982d81..13b0fd6403d 100644 --- a/apps/dashboard/src/lib/sdk.ts +++ b/apps/dashboard/src/lib/sdk.ts @@ -1,12 +1,12 @@ -import { getThirdwebClient } from "@/constants/thirdweb.server"; +import type { ThirdwebClient } from "thirdweb"; import { resolveScheme } from "thirdweb/storage"; -export function replaceIpfsUrl(uri: string) { +export function replaceIpfsUrl(uri: string, client: ThirdwebClient) { try { // eslint-disable-next-line no-restricted-syntax return resolveScheme({ uri, - client: getThirdwebClient(), + client, }); } catch (err) { console.error("error resolving ipfs url", uri, err); diff --git a/apps/dashboard/src/lib/wallet/nfts/alchemy.ts b/apps/dashboard/src/lib/wallet/nfts/alchemy.ts index 13bb4608ee2..36b5e0b9f79 100644 --- a/apps/dashboard/src/lib/wallet/nfts/alchemy.ts +++ b/apps/dashboard/src/lib/wallet/nfts/alchemy.ts @@ -1,21 +1,16 @@ -import { getThirdwebClient } from "@/constants/thirdweb.server"; +import "server-only"; + import { download } from "thirdweb/storage"; import type { NFTMetadata } from "thirdweb/utils"; +import { getUserThirdwebClient } from "../../../app/api/lib/getAuthToken"; import { handleArbitraryTokenURI, shouldDownloadURI } from "./tokenUri"; import { type AlchemySupportedChainId, type GenerateURLParams, type WalletNFT, - alchemySupportedChainIds, alchemySupportedChainIdsMap, } from "./types"; -export function isAlchemySupported( - chainId: number, -): chainId is AlchemySupportedChainId { - return alchemySupportedChainIds.includes(chainId.toString()); -} - export function generateAlchemyUrl({ chainId, owner }: GenerateURLParams) { const url = new URL( `https://${ @@ -30,6 +25,8 @@ export async function transformAlchemyResponseToNFT( alchemyResponse: AlchemyResponse, owner: string, ): Promise { + const client = await getUserThirdwebClient(); + return ( await Promise.all( alchemyResponse.ownedNfts.map(async (alchemyNFT) => { @@ -42,7 +39,7 @@ export async function transformAlchemyResponseToNFT( metadata: shouldDownloadURI(rawUri) ? await download({ uri: handleArbitraryTokenURI(rawUri), - client: getThirdwebClient(), + client, }) .then((res) => res.json()) .catch(() => ({})) diff --git a/apps/dashboard/src/lib/wallet/nfts/isAlchemySupported.ts b/apps/dashboard/src/lib/wallet/nfts/isAlchemySupported.ts new file mode 100644 index 00000000000..8f3629a6377 --- /dev/null +++ b/apps/dashboard/src/lib/wallet/nfts/isAlchemySupported.ts @@ -0,0 +1,10 @@ +import { + type AlchemySupportedChainId, + alchemySupportedChainIds, +} from "./types"; + +export function isAlchemySupported( + chainId: number, +): chainId is AlchemySupportedChainId { + return alchemySupportedChainIds.includes(chainId.toString()); +} diff --git a/apps/dashboard/src/lib/wallet/nfts/isMoralisSupported.ts b/apps/dashboard/src/lib/wallet/nfts/isMoralisSupported.ts new file mode 100644 index 00000000000..d319202e245 --- /dev/null +++ b/apps/dashboard/src/lib/wallet/nfts/isMoralisSupported.ts @@ -0,0 +1,10 @@ +import { + type MoralisSupportedChainId, + moralisSupportedChainIds, +} from "./types"; + +export function isMoralisSupported( + chainId: number, +): chainId is MoralisSupportedChainId { + return moralisSupportedChainIds.includes(chainId.toString()); +} diff --git a/apps/dashboard/src/lib/wallet/nfts/moralis.ts b/apps/dashboard/src/lib/wallet/nfts/moralis.ts index 5d2824fd913..b6530e6f523 100644 --- a/apps/dashboard/src/lib/wallet/nfts/moralis.ts +++ b/apps/dashboard/src/lib/wallet/nfts/moralis.ts @@ -1,18 +1,9 @@ -import { getThirdwebClient } from "@/constants/thirdweb.server"; +import "server-only"; + import { download } from "thirdweb/storage"; +import { getUserThirdwebClient } from "../../../app/api/lib/getAuthToken"; import { handleArbitraryTokenURI, shouldDownloadURI } from "./tokenUri"; -import { - type GenerateURLParams, - type MoralisSupportedChainId, - type WalletNFT, - moralisSupportedChainIds, -} from "./types"; - -export function isMoralisSupported( - chainId: number, -): chainId is MoralisSupportedChainId { - return moralisSupportedChainIds.includes(chainId.toString()); -} +import type { GenerateURLParams, WalletNFT } from "./types"; export function generateMoralisUrl({ chainId, owner }: GenerateURLParams) { const url = new URL(`https://deep-index.moralis.io/api/v2/${owner}/nft`); @@ -28,6 +19,8 @@ export async function transformMoralisResponseToNFT( owner: string, chainId: number, ): Promise { + const client = await getUserThirdwebClient(); + return ( await Promise.all( moralisResponse.result.map(async (moralisNft) => { @@ -39,7 +32,7 @@ export async function transformMoralisResponseToNFT( metadata: shouldDownloadURI(moralisNft.token_uri) ? await download({ uri: handleArbitraryTokenURI(moralisNft.token_uri), - client: getThirdwebClient(), + client, }) .then((res) => res.json()) .catch(() => ({})) diff --git a/apps/dashboard/src/stories/utils.tsx b/apps/dashboard/src/stories/utils.tsx index 3673008d9a5..047fe616122 100644 --- a/apps/dashboard/src/stories/utils.tsx +++ b/apps/dashboard/src/stories/utils.tsx @@ -1,5 +1,6 @@ import { Badge } from "@/components/ui/badge"; import { INITIAL_VIEWPORTS } from "@storybook/addon-viewport"; +import { getThirdwebClient } from "../@/constants/thirdweb.server"; function StoryBadge(props: { label: string; @@ -42,3 +43,8 @@ export function storybookLog(...mesages: unknown[]) { ...mesages, ); } + +export const storybookThirdwebClient = getThirdwebClient({ + jwt: null, + teamId: undefined, +});