diff --git a/apps/dashboard/src/@/components/blocks/TokenSelector.tsx b/apps/dashboard/src/@/components/blocks/TokenSelector.tsx index f42a704bf3f..228bc161fbe 100644 --- a/apps/dashboard/src/@/components/blocks/TokenSelector.tsx +++ b/apps/dashboard/src/@/components/blocks/TokenSelector.tsx @@ -11,9 +11,9 @@ import { SelectWithSearch } from "@/components/blocks/select-with-search"; import { Badge } from "@/components/ui/badge"; import { useAllChainsData } from "@/hooks/chains/allChains"; import { useTokensData } from "@/hooks/tokens"; -import { replaceIpfsUrl } from "@/lib/sdk"; import { cn } from "@/lib/utils"; import { fallbackChainIcon } from "@/utils/chain-icons"; +import { resolveSchemeWithErrorHandler } from "@/utils/resolveSchemeWithErrorHandler"; import { Spinner } from "../ui/Spinner/Spinner"; type Option = { label: string; value: string }; @@ -122,7 +122,10 @@ export function TokenSelector(props: { return option.label; } const resolvedSrc = token.iconUri - ? replaceIpfsUrl(token.iconUri, props.client) + ? resolveSchemeWithErrorHandler({ + client: props.client, + uri: token.iconUri, + }) : fallbackChainIcon; return ( diff --git a/apps/dashboard/src/@/components/contract-components/contract-deploy-form/platform-fee-fieldset.tsx b/apps/dashboard/src/@/components/contract-components/contract-deploy-form/platform-fee-fieldset.tsx index 676450aaff8..4c220a7ce32 100644 --- a/apps/dashboard/src/@/components/contract-components/contract-deploy-form/platform-fee-fieldset.tsx +++ b/apps/dashboard/src/@/components/contract-components/contract-deploy-form/platform-fee-fieldset.tsx @@ -1,8 +1,8 @@ -import Link from "next/link"; import type { ThirdwebClient } from "thirdweb"; import { BasisPointsInput } from "@/components/blocks/BasisPointsInput"; import { FormFieldSetup } from "@/components/blocks/FormFieldSetup"; import { SolidityInput } from "@/components/solidity-inputs"; +import { UnderlineLink } from "@/components/ui/UnderlineLink"; import { Fieldset } from "./common"; import type { CustomContractDeploymentForm } from "./custom-contract"; @@ -78,30 +78,28 @@ export const PlatformFeeFieldset: React.FC = ({ ) : isMarketplace ? ( -

+

A 2.5% platform fee is deducted from each sale to support ongoing - platform operations and improvements.{" "} - + See fee breakdown on pricing page. - +

) : ( -

+

A 2.5% platform fee is deducted from each primary sale price to - support ongoing platform operations and improvements.{" "} - + See fee breakdown on pricing page. - +

)} diff --git a/apps/dashboard/src/@/components/contract-components/publisher/publisher-header.tsx b/apps/dashboard/src/@/components/contract-components/publisher/publisher-header.tsx index 823830499f1..226b7631c14 100644 --- a/apps/dashboard/src/@/components/contract-components/publisher/publisher-header.tsx +++ b/apps/dashboard/src/@/components/contract-components/publisher/publisher-header.tsx @@ -1,12 +1,11 @@ "use client"; -import { ExternalLinkIcon } from "lucide-react"; +import { Edit3Icon } from "lucide-react"; import Link from "next/link"; import { type ThirdwebClient, ZERO_ADDRESS } from "thirdweb"; import { AccountAddress, AccountAvatar, - AccountBlobbie, AccountName, AccountProvider, } from "thirdweb/react"; @@ -15,77 +14,69 @@ import { useEns } from "@/hooks/contract-hooks"; import { replaceDeployerAddress } from "@/lib/publisher-utils"; import { shortenIfAddress } from "@/utils/usedapp-external"; -interface PublisherHeaderProps { - wallet: string; - client: ThirdwebClient; -} -export const PublisherHeader: React.FC = ({ +export function PublisherLink({ wallet, client, -}) => { +}: { + wallet: string; + client: ThirdwebClient; +}) { const ensQuery = useEns({ addressOrEnsName: wallet, client, }); return ( -
-

Published by

- -
-
- - } - loadingComponent={ - - } - /> -
- -
- - - {ensQuery.data?.ensName} - - ) : ( - - shortenIfAddress(replaceDeployerAddress(addr)) - } - /> - ) - } - formatFn={(name) => replaceDeployerAddress(name)} - loadingComponent={} - /> - + +
+
+ + +
+ } + loadingComponent={} + /> +
- - View all published contracts{" "} - - + +
+ Published by
-
- -
+ + + {ensQuery.data?.ensName} + + ) : ( + + shortenIfAddress(replaceDeployerAddress(addr)) + } + /> + ) + } + formatFn={(name) => replaceDeployerAddress(name)} + loadingComponent={} + /> + +
+ ); -}; +} 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 dd01631d2a7..52a6318a546 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 @@ -5,7 +5,7 @@ import Image from "next/image"; import type { FetchDeployMetadataResult } from "thirdweb/contract"; import { DASHBOARD_THIRDWEB_SECRET_KEY } from "@/constants/server-envs"; import { getConfiguredThirdwebClient } from "@/constants/thirdweb.server"; -import { replaceIpfsUrl } from "@/lib/sdk"; +import { resolveSchemeWithErrorHandler } from "@/utils/resolveSchemeWithErrorHandler"; import generalContractIcon from "../../../../../public/assets/tw-icons/general.png"; type ContractIdImageProps = { @@ -29,13 +29,13 @@ export const ContractIdImage: React.FC = ({ className="size-8 rounded-full" src={ DASHBOARD_THIRDWEB_SECRET_KEY - ? replaceIpfsUrl( - logo, - getConfiguredThirdwebClient({ + ? resolveSchemeWithErrorHandler({ + client: getConfiguredThirdwebClient({ secretKey: DASHBOARD_THIRDWEB_SECRET_KEY, teamId: undefined, }), - ) + uri: logo, + }) : logo } /> diff --git a/apps/dashboard/src/@/components/contracts/code-overview.tsx b/apps/dashboard/src/@/components/contracts/code-overview.tsx index d6c679508e4..7283382a26b 100644 --- a/apps/dashboard/src/@/components/contracts/code-overview.tsx +++ b/apps/dashboard/src/@/components/contracts/code-overview.tsx @@ -657,7 +657,7 @@ export function CodeOverview(props: {
-

+

{isAccountFactory ? "Direct contract interaction (advanced)" : chainInfo @@ -851,7 +851,7 @@ function AccentButton(props: { return (

); } @@ -222,6 +224,8 @@ type ExtensionFunctions = { functions: AbiFunction[]; }; +type ReadOrWriteTab = "read" | "write"; + export const ContractFunctionsPanel: React.FC = ({ fnsOrEvents, contract, @@ -280,14 +284,21 @@ export const ContractFunctionsPanel: React.FC = ({ return fnsOrEvents.filter((fn) => !("stateMutability" in fn)) as AbiEvent[]; }, [fnsOrEvents]); + const defaultSelected = fnsOrEvents[0]; + const [selectedFunction, setSelectedFunction] = useState< AbiFunction | AbiEvent | undefined - >(fnsOrEvents[0]); + >(defaultSelected); const [_keywordSearch, setKeywordSearch] = useState(""); const [keywordSearch] = useDebounce(_keywordSearch, 150); - const [activeTab, setActiveTab] = useState(0); + const [activeTab, setActiveTab] = useState(() => { + const isDefaultSelectedReadFunction = viewFunctions.find((e) => + e.functions.find((fn) => fn.name === defaultSelected?.name), + ); + return isDefaultSelectedReadFunction ? "read" : "write"; + }); const functionSection = (e: ExtensionFunctions) => { const filteredFunctions = keywordSearch @@ -298,7 +309,7 @@ export const ContractFunctionsPanel: React.FC = ({ return (
-
+
{selectedFunction && filteredFunctions.map((fn) => ( = ({ }; return ( -
+
{/* left */} -
+
{(writeFunctions.length > 0 || viewFunctions.length > 0) && (
0 + ...(viewFunctions.length > 0 ? [ { - name: "Write", - onClick: () => setActiveTab(0), - isActive: activeTab === 0, + name: "Read", + onClick: () => setActiveTab("read"), + isActive: activeTab === "read", }, ] : []), - ...(viewFunctions.length > 0 + ...(writeFunctions.length > 0 ? [ { - name: "Read", - onClick: () => setActiveTab(1), - isActive: activeTab === 1, + name: "Write", + onClick: () => setActiveTab("write"), + isActive: activeTab === "write", }, ] : []), @@ -357,18 +368,19 @@ export const ContractFunctionsPanel: React.FC = ({
- {activeTab === 0 && + {activeTab === "write" && writeFunctions.length > 0 && writeFunctions.map((e) => functionSection(e))} - {activeTab === 1 && + {activeTab === "read" && viewFunctions.length > 0 && viewFunctions.map((e) => functionSection(e))}
)} + {events.length > 0 && selectedFunction && ( -
+
{events.map((fn) => ( = ({
{/* right */} -
+
{selectedFunction && ( = ({ return (
)} {events && events.length > 0 && activeTab === "events" && ( - +
+ +
)} {abi && activeTab === "code" && ( diff --git a/apps/dashboard/src/@/components/contracts/published-contract/index.tsx b/apps/dashboard/src/@/components/contracts/published-contract/index.tsx index bf7d93a0752..69ae9851054 100644 --- a/apps/dashboard/src/@/components/contracts/published-contract/index.tsx +++ b/apps/dashboard/src/@/components/contracts/published-contract/index.tsx @@ -6,27 +6,24 @@ import { BookOpenTextIcon, CalendarDaysIcon, ExternalLinkIcon, - PencilIcon, ServerIcon, ShieldCheckIcon, } from "lucide-react"; import Link from "next/link"; import { useMemo } from "react"; import type { ThirdwebClient } from "thirdweb"; -import { useActiveAccount } from "thirdweb/react"; import { download } from "thirdweb/storage"; import invariant from "tiny-invariant"; -import { PublisherHeader } from "@/components//contract-components/publisher/publisher-header"; +import { PublisherLink } from "@/components//contract-components/publisher/publisher-header"; import { MarkdownRenderer } from "@/components/blocks/markdown-renderer"; import type { PublishedContractWithVersion } from "@/components/contract-components/fetch-contracts-with-versions"; import { ContractFunctionsOverview } from "@/components/contracts/functions/contract-functions"; -import { Button } from "@/components/ui/button"; import { usePublishedContractEvents, usePublishedContractFunctions, } from "@/hooks/contract-hooks"; import { correctAndUniqueLicenses } from "@/lib/licenses"; -import { replaceIpfsUrl } from "@/lib/sdk"; +import { publicIPFSGateway } from "@/lib/sdk"; import { cn } from "@/lib/utils"; type ExtendedPublishedContract = PublishedContractWithVersion & { @@ -44,15 +41,13 @@ export function PublishedContract({ publishedContract, isLoggedIn, client, - className, + maxWidthClassName, }: { publishedContract: ExtendedPublishedContract; isLoggedIn: boolean; client: ThirdwebClient; - className?: string; + maxWidthClassName?: string; }) { - const address = useActiveAccount()?.address; - const contractFunctions = usePublishedContractFunctions(publishedContract); const contractEvents = usePublishedContractEvents(publishedContract); @@ -103,171 +98,133 @@ export function PublishedContract({ ); return ( -
- {/* left */} -
- {address === publishedContract.publisher && ( -
- -
- )} - - {/* readme */} - {publishedContract?.readme && ( -
- -
- )} - - {/* changelog */} - {publishedContract?.changelog && ( -
-
-

- {publishedContract?.version} Release Notes -

-
- + {/* right side content moved below changelog */} + {publishedContract.publisher && ( +
+
+ -
- )} - - {contractFunctions && ( - - )} -
- - {/* right */} -
- {publishedContract.publisher && ( - - )} -
+
    + {/* timestamp */} + {publishedContract.publishTimestamp && ( +
  • +
    + +
    +
    +
    Publish Date
    +

    + {publishDate} +

    +
    +
  • + )} -
      - {/* timestamp */} - {publishedContract.publishTimestamp && ( -
    • -
      - -
      -
      -
      - Publish Date -
      -

      - {publishDate} -

      -
      -
    • - )} + {/* audit */} + {publishedContract?.audit && ( +
    • +
      +
      + +
      +
      +
      Audit Report
      + + View Audit Report + + +
      +
      +
    • + )} - {/* audit */} - {publishedContract?.audit && ( -
    • -
      + {/* license */} +
    • - +
      -
      -
      - Audit Report +
      +
      + License{licenses.length > 1 ? "s" : ""}
      - - View Audit Report - - +

      + {licenses.join(", ") || "None"} +

      -
      -
    • - )} + - {/* license */} -
    • -
      - -
      -
      -
      - License{licenses.length > 1 ? "s" : ""} -
      -

      - {licenses.join(", ") || "None"} -

      + {(publishedContract?.isDeployableViaProxy && + hasImplementationAddresses) || + (publishedContract?.isDeployableViaFactory && + hasFactoryAddresses) ? ( +
    • +
      + +
      +
      + {publishedContract?.isDeployableViaFactory + ? "Factory" + : "Proxy"}{" "} + Enabled +
      +
    • + ) : null} +
    +
+
+ )} + +
+ {/* main content */} +
+ {/* readme */} + {publishedContract?.readme && ( +
+
- + )} - {(publishedContract?.isDeployableViaProxy && - hasImplementationAddresses) || - (publishedContract?.isDeployableViaFactory && hasFactoryAddresses) ? ( -
  • -
    - + {/* changelog */} + {publishedContract?.changelog && ( +
    +
    +

    + {publishedContract?.version} Release Notes +

    -
    - {publishedContract?.isDeployableViaFactory - ? "Factory" - : "Proxy"}{" "} - Enabled -
    -
  • - ) : null} - - -
    + +
    + )} - + {contractFunctions && ( + + )} +
    ); diff --git a/apps/dashboard/src/@/icons/ChainIcon.tsx b/apps/dashboard/src/@/icons/ChainIcon.tsx index fef285a6635..9ef4f7b4693 100644 --- a/apps/dashboard/src/@/icons/ChainIcon.tsx +++ b/apps/dashboard/src/@/icons/ChainIcon.tsx @@ -2,10 +2,9 @@ import type { ThirdwebClient } from "thirdweb"; import { Img } from "@/components/blocks/Img"; -/* eslint-disable @next/next/no-img-element */ -import { replaceIpfsUrl } from "@/lib/sdk"; import { cn } from "@/lib/utils"; import { fallbackChainIcon } from "@/utils/chain-icons"; +import { resolveSchemeWithErrorHandler } from "@/utils/resolveSchemeWithErrorHandler"; type ImageProps = React.ComponentProps<"img">; @@ -19,7 +18,12 @@ export const ChainIconClient = ({ src, ...restProps }: ChainIconProps) => { - const resolvedSrc = src ? replaceIpfsUrl(src, client) : fallbackChainIcon; + const resolvedSrc = src + ? resolveSchemeWithErrorHandler({ + client, + uri: src, + }) + : fallbackChainIcon; return ( = ({ return (
    {functions && functions.length > 0 ? ( - ) : (
    diff --git a/apps/dashboard/src/app/(app)/(dashboard)/profile/[addressOrEns]/components/PublishedContractTable.tsx b/apps/dashboard/src/app/(app)/(dashboard)/profile/[addressOrEns]/components/PublishedContractTable.tsx index bd17dc6536c..231e7e2d415 100644 --- a/apps/dashboard/src/app/(app)/(dashboard)/profile/[addressOrEns]/components/PublishedContractTable.tsx +++ b/apps/dashboard/src/app/(app)/(dashboard)/profile/[addressOrEns]/components/PublishedContractTable.tsx @@ -19,7 +19,8 @@ import { import { ToolTipLabel } from "@/components/ui/tooltip"; import type { PublishedContractDetails } from "@/hooks/contract-hooks"; import { replaceDeployerAddress } from "@/lib/publisher-utils"; -import { replaceIpfsUrl } from "@/lib/sdk"; +import { publicIPFSGateway } from "@/lib/sdk"; +import { resolveSchemeWithErrorHandler } from "@/utils/resolveSchemeWithErrorHandler"; interface PublishedContractTableProps { contractDetails: ContractDataInput[]; @@ -62,7 +63,14 @@ export function PublishedContractTable(props: PublishedContractTableProps) { fallback={
    } - src={cell.value ? replaceIpfsUrl(cell.value, props.client) : ""} + src={ + cell.value + ? resolveSchemeWithErrorHandler({ + client: props.client, + uri: cell.value, + }) + : "" + } /> ), Header: "Logo", @@ -116,7 +124,7 @@ export function PublishedContractTable(props: PublishedContractTableProps) { > { e.stopPropagation(); }} diff --git a/apps/dashboard/src/app/(app)/(dashboard)/published-contract/[publisher]/[contract_id]/[version]/page.tsx b/apps/dashboard/src/app/(app)/(dashboard)/published-contract/[publisher]/[contract_id]/[version]/page.tsx index 8f9e5d48405..45e7eb50e12 100644 --- a/apps/dashboard/src/app/(app)/(dashboard)/published-contract/[publisher]/[contract_id]/[version]/page.tsx +++ b/apps/dashboard/src/app/(app)/(dashboard)/published-contract/[publisher]/[contract_id]/[version]/page.tsx @@ -1,7 +1,10 @@ import { notFound } from "next/navigation"; import { isAddress } from "thirdweb"; import { resolveAddress } from "thirdweb/extensions/ens"; -import { getUserThirdwebClient } from "@/api/auth-token"; +import { + getAuthTokenWalletAddress, + getUserThirdwebClient, +} from "@/api/auth-token"; import { fetchPublishedContractVersions } from "@/components/contract-components/fetch-contracts-with-versions"; import { PublishedContract } from "@/components/contracts/published-contract"; import { serverThirdwebClient } from "@/constants/thirdweb-client.server"; @@ -29,6 +32,7 @@ export default async function PublishedContractPage( props: PublishedContractDeployPageProps, ) { const params = await props.params; + const accountAddress = await getAuthTokenWalletAddress(); // resolve ENS if required let publisherAddress: string | undefined; @@ -75,15 +79,16 @@ export default async function PublishedContractPage( return (
    - +
    -
    +
    - +
    -
    +
    , ) { return ( -
    +
    -
    +
    {props.children} + + {props.accountAddress === props.activeVersion.publisher && ( + + )}
    diff --git a/apps/dashboard/src/app/(app)/(dashboard)/published-contract/components/publish-based-deploy.tsx b/apps/dashboard/src/app/(app)/(dashboard)/published-contract/components/publish-based-deploy.tsx index 877c609b88f..cbdde0c37fd 100644 --- a/apps/dashboard/src/app/(app)/(dashboard)/published-contract/components/publish-based-deploy.tsx +++ b/apps/dashboard/src/app/(app)/(dashboard)/published-contract/components/publish-based-deploy.tsx @@ -1,6 +1,7 @@ import { isAddress } from "thirdweb"; import { fetchDeployMetadata } from "thirdweb/contract"; import { resolveAddress } from "thirdweb/extensions/ens"; +import { getAuthTokenWalletAddress } from "@/api/auth-token"; import { fetchPublishedContractVersion, fetchPublishedContractVersions, @@ -26,6 +27,8 @@ function mapThirdwebPublisher(publisher: string) { } export async function DeployFormForPublishInfo(props: PublishBasedDeployProps) { + const accountAddress = await getAuthTokenWalletAddress(); + // resolve ENS if required const publisherAddress = isAddress(props.publisher) ? props.publisher @@ -104,6 +107,7 @@ export async function DeployFormForPublishInfo(props: PublishBasedDeployProps) { activeVersion={publishedContract} allVersions={publishedContractVersions} className="container max-w-5xl" + accountAddress={accountAddress || undefined} />
    diff --git a/apps/dashboard/src/app/(app)/(dashboard)/published-contract/components/version-selector.tsx b/apps/dashboard/src/app/(app)/(dashboard)/published-contract/components/version-selector.tsx index 3c257d8a2c2..faa2e21cc80 100644 --- a/apps/dashboard/src/app/(app)/(dashboard)/published-contract/components/version-selector.tsx +++ b/apps/dashboard/src/app/(app)/(dashboard)/published-contract/components/version-selector.tsx @@ -57,7 +57,7 @@ export function DeployContractVersionSelector({ }} value={version} > - +