diff --git a/apps/dashboard/src/components/contract-functions/contract-function-comment.tsx b/apps/dashboard/src/components/contract-functions/contract-function-comment.tsx new file mode 100644 index 00000000000..79373af931e --- /dev/null +++ b/apps/dashboard/src/components/contract-functions/contract-function-comment.tsx @@ -0,0 +1,76 @@ +import { CodeBlock } from "@/components/ui/CodeBlock"; +import { Badge } from "@/components/ui/badge"; +import { useContractSources } from "contract-ui/hooks/useContractSources"; +import { useMemo } from "react"; +import type { ThirdwebContract } from "thirdweb"; + +/** + * Take in a contract & function, try to fetch the comment of that function + */ +export default function ContractFunctionComment({ + contract, + functionName, +}: { contract: ThirdwebContract; functionName: string }) { + const sourceQuery = useContractSources(contract); + const comment = useMemo(() => { + if (!sourceQuery.data?.length) { + return null; + } + const file = sourceQuery.data.find((item) => + item.source.includes(functionName), + ); + if (!file) { + return null; + } + return extractFunctionComment(file.source, functionName); + }, [sourceQuery.data, functionName]); + + if (sourceQuery.isLoading) { + return null; + } + if (!comment) { + return null; + } + return ( + <> +

+ About this function Beta +

+ + + ); +} + +function extractFunctionComment( + // Tthe whole code from the solidity file containing (possibly) the function + solidityCode: string, + functionName: string, +): string | null { + // Regular expression to match function declarations and their preceding comments + // This regex now captures both single-line (//) and multi-line (/** */) comments + const functionRegex = + /(?:\/\/[^\n]*|\/\*\*[\s\S]*?\*\/)\s*function\s+(\w+)\s*\(/g; + + while (true) { + const match = functionRegex.exec(solidityCode); + if (match === null) { + return null; + } + const [fullMatch, name] = match; + if (!fullMatch || !fullMatch.length) { + return null; + } + if (name === functionName) { + // Extract the comment part + const comment = (fullMatch.split("function")[0] || "").trim(); + if (!comment) { + return null; + } + + if (/^[^a-zA-Z0-9]+$/.test(comment)) { + return null; + } + return comment; + } + } +} diff --git a/apps/dashboard/src/components/contract-functions/contract-function.tsx b/apps/dashboard/src/components/contract-functions/contract-function.tsx index c87efc631ea..6e6e24dd00b 100644 --- a/apps/dashboard/src/components/contract-functions/contract-function.tsx +++ b/apps/dashboard/src/components/contract-functions/contract-function.tsx @@ -29,7 +29,13 @@ import type { AbiEvent, AbiFunction } from "abitype"; import { camelToTitle } from "contract-ui/components/solidity-inputs/helpers"; import { SearchIcon } from "lucide-react"; import { usePathname, useSearchParams } from "next/navigation"; -import { type Dispatch, type SetStateAction, useMemo, useState } from "react"; +import { + type Dispatch, + type SetStateAction, + lazy, + useMemo, + useState, +} from "react"; import type { ThirdwebContract } from "thirdweb"; import * as ERC20Ext from "thirdweb/extensions/erc20"; import * as ERC721Ext from "thirdweb/extensions/erc721"; @@ -47,6 +53,9 @@ import { CodeSegment } from "../contract-tabs/code/CodeSegment"; import type { CodeEnvironment } from "../contract-tabs/code/types"; import { InteractiveAbiFunction } from "./interactive-abi-function"; +const ContractFunctionComment = lazy( + () => import("./contract-function-comment"), +); interface ContractFunctionProps { fn: AbiFunction | AbiEvent; contract: ThirdwebContract; @@ -136,7 +145,6 @@ function ContractFunctionInner({ contract, fn }: ContractFunctionProps) { /> )} - {isFunction && ( )} + ); }