Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,18 @@ import {
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { getThirdwebClient } from "@/constants/thirdweb.server";
import { ChevronDownIcon, TicketCheckIcon } from "lucide-react";
import type { Metadata } from "next";
import Link from "next/link";
import { redirect } from "next/navigation";
import { mapV4ChainToV5Chain } from "../../../../../contexts/map-chains";
import { getAuthToken } from "../../../../api/lib/getAuthToken";
import { getRawAccount } from "../../../../account/settings/getAccount";
import {
getAuthToken,
getAuthTokenWalletAddress,
} from "../../../../api/lib/getAuthToken";
import { NebulaFloatingChatButton } from "../../../../nebula-app/(app)/components/FloatingChat/FloatingChat";
import { StarButton } from "../../components/client/star-button";
import { getChain, getChainMetadata } from "../../utils";
import { AddChainToWallet } from "./components/client/add-chain-to-wallet";
Expand Down Expand Up @@ -55,17 +61,58 @@ export default async function ChainPageLayout(props: {
}) {
const params = await props.params;
const { children } = props;
const chain = await getChain(params.chain_id);
const authToken = await getAuthToken();
const [chain, authToken, account, accountAddress] = await Promise.all([
getChain(params.chain_id),
getAuthToken(),
getRawAccount(),
getAuthTokenWalletAddress(),
]);

if (params.chain_id !== chain.slug) {
redirect(chain.slug);
}

const chainMetadata = await getChainMetadata(chain.chainId);
const client = getThirdwebClient(authToken ?? undefined);

const chainPromptPrefix = `\
You are assisting users exploring the chain ${chain.name} (Chain ID: ${chain.chainId}). Provide concise insights into the types of applications and activities prevalent on this chain, such as DeFi protocols, NFT marketplaces, or gaming platforms. Highlight notable projects or trends without delving into technical details like consensus mechanisms or gas fees.
Users may seek comparisons between ${chain.name} and other chains. Provide objective, succinct comparisons focusing on performance, fees, and ecosystem support. Refrain from transaction-specific advice unless requested.
Provide users with an understanding of the unique use cases and functionalities that ${chain.name} supports. Discuss how developers leverage this chain for specific applications, such as scalable dApps, low-cost transactions, or specialized token standards, focusing on practical implementations.
Users may be interested in utilizing thirdweb tools on ${chain.name}. Offer clear guidance on how thirdweb's SDKs, smart contract templates, and deployment tools integrate with this chain. Emphasize the functionalities enabled by thirdweb without discussing transaction execution unless prompted.
Avoid transaction-related actions to be executed by the user unless inquired about.

The following is the user's message:
`;

const examplePrompts: string[] = [
"What are users doing on this chain?",
"What are the most active contracts?",
"Why would I use this chain over others?",
"Can I deploy thirdweb contracts to this chain?",
];

if (chain.chainId !== 1) {
examplePrompts.push("Can I bridge assets from Ethereum to this chain?");
}

return (
<>
<NebulaFloatingChatButton
authToken={authToken ?? undefined}
account={account}
label="Ask AI about this chain"
client={client}
nebulaParams={{
messagePrefix: chainPromptPrefix,
chainIds: [chain.chainId],
wallet: accountAddress ?? undefined,
}}
examplePrompts={examplePrompts.map((prompt) => ({
title: prompt,
message: prompt,
}))}
/>
<div className="flex h-14 border-border border-b pl-7">
<Breadcrumb className="my-auto">
<BreadcrumbList>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ import { isAddress, isContractDeployed } from "thirdweb/utils";
import type { MinimalTeamsAndProjects } from "../../../../../components/contract-components/contract-deploy-form/add-to-project-card";
import { resolveFunctionSelectors } from "../../../../../lib/selectors";
import { shortenIfAddress } from "../../../../../utils/usedapp-external";
import { getRawAccount } from "../../../../account/settings/getAccount";
import {
getAuthToken,
getAuthTokenWalletAddress,
} from "../../../../api/lib/getAuthToken";
import { NebulaFloatingChatButton } from "../../../../nebula-app/(app)/components/FloatingChat/FloatingChat";
import { ConfigureCustomChain } from "./_layout/ConfigureCustomChain";
import { getContractMetadataHeaderData } from "./_layout/contract-metadata";
import { ContractPageLayout } from "./_layout/contract-page-layout";
Expand Down Expand Up @@ -42,6 +48,12 @@ export default async function Layout(props: {
notFound();
}

const [authToken, account, accountAddress] = await Promise.all([
getAuthToken(),
getRawAccount(),
getAuthTokenWalletAddress(),
]);

const client = getThirdwebClient();
const teamsAndProjects = await getTeamsAndProjectsIfLoggedIn();

Expand Down Expand Up @@ -75,6 +87,25 @@ export default async function Layout(props: {
const { contractMetadata, externalLinks } =
await getContractMetadataHeaderData(contract);

const contractAddress = info.contract.address;
const chainName = info.chainMetadata.name;
const chainId = info.contract.chain.id;

const contractPromptPrefix = `A user is viewing the contract address ${contractAddress} on ${chainName} (Chain ID: ${chainId}). Provide a concise summary of this contract's functionalities, such as token minting, staking, or governance mechanisms. Focus on what the contract enables users to do, avoiding transaction execution details unless requested.
Users may be interested in how to interact with the contract. Outline common interaction patterns, such as claiming rewards, participating in governance, or transferring assets. Emphasize the contract's capabilities without guiding through transaction processes unless asked.
Provide insights into how the contract is being used. Share information on user engagement, transaction volumes, or integration with other dApps, focusing on the contract's role within the broader ecosystem.
Users may be considering integrating the contract into their applications. Discuss how this contract's functionalities can be leveraged within different types of dApps, highlighting potential use cases and benefits.

The following is the user's message:`;

const examplePrompts: string[] = [
"What does this contract do?",
"What permissions or roles exist in this contract?",
"Which functions are used the most?",
"Has this contract been used recently?",
"Who are the largest holders/users of this?",
];

return (
<ContractPageLayout
chainMetadata={chainMetadata}
Expand All @@ -85,6 +116,21 @@ export default async function Layout(props: {
teamsAndProjects={teamsAndProjects}
client={client}
>
<NebulaFloatingChatButton
authToken={authToken ?? undefined}
account={account}
label="Ask AI about this contract"
client={client}
nebulaParams={{
messagePrefix: contractPromptPrefix,
chainIds: [info.contract.chain.id],
wallet: accountAddress ?? undefined,
}}
examplePrompts={examplePrompts.map((prompt) => ({
title: prompt,
message: prompt,
}))}
/>
{props.children}
</ContractPageLayout>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,17 @@ export function ChatBar(props: {
isChatStreaming: boolean;
abortChatStream: () => void;
prefillMessage: string | undefined;
className?: string;
}) {
const [message, setMessage] = useState(props.prefillMessage || "");

return (
<div className="rounded-2xl border border-border bg-card p-2">
<div
className={cn(
"rounded-2xl border border-border bg-card p-2",
props.className,
)}
>
<div className="max-h-[70vh] overflow-y-auto">
<AutoResizeTextarea
placeholder={"Ask Nebula"}
Expand Down
Loading
Loading