Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Dashboard] Feature: UI for crosschain modules #5399

Open
wants to merge 51 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
fe50d84
UI for crosschain modules
GWSzeto Nov 8, 2024
d14ec4b
Merge remote-tracking branch 'origin/main' into crosschain-ui
GWSzeto Nov 25, 2024
d442dfe
Merge remote-tracking branch 'origin/main' into crosschain-ui
GWSzeto Nov 26, 2024
c4acff6
Merge remote-tracking branch 'origin/main' into crosschain-ui
GWSzeto Nov 27, 2024
9fedac3
WIP: hardcoded modified version of TWCloneFactory to be used
GWSzeto Nov 27, 2024
4595d58
WIP: TODO's created to fetch for ContractInitialized event and update…
GWSzeto Nov 30, 2024
d08b33c
WIP: Testing out deploying bare core contract with modules installed …
GWSzeto Dec 4, 2024
9f5289b
Merge remote-tracking branch 'origin/main' into crosschain-ui
GWSzeto Dec 4, 2024
1f74bf6
WIP: staging to get help
GWSzeto Dec 5, 2024
3248212
successfully deploys using the initialize data from the event
GWSzeto Dec 6, 2024
6b9dd33
able to install modules successfully when crosschain deploying
GWSzeto Dec 6, 2024
64ca579
updated to be promise.allSettled when installing modules to not block…
GWSzeto Dec 6, 2024
9143857
removing console logs
GWSzeto Dec 6, 2024
051028b
fixing liniting issues
GWSzeto Dec 6, 2024
97e6b99
fixed linting issues
GWSzeto Dec 6, 2024
55158b4
created isSuperchain and isCrosschain flag in favour of case switch s…
GWSzeto Dec 9, 2024
67db04d
god bless greg it works
GWSzeto Dec 10, 2024
f6ee6a2
Merge remote-tracking branch 'origin/main' into crosschain-ui
GWSzeto Dec 10, 2024
828c198
addressed comments in PR
GWSzeto Dec 11, 2024
429d10c
updated wording
GWSzeto Dec 11, 2024
71b8a97
updated superchain bridge address
GWSzeto Dec 11, 2024
3cc27b6
Merge remote-tracking branch 'origin/main' into crosschain-ui
GWSzeto Dec 13, 2024
1a7f7cb
updated to show links
GWSzeto Dec 14, 2024
ec1a0a1
implemented cross chain transfers
GWSzeto Dec 17, 2024
52c3f44
tweaked input + button on crosschain transfer for OP Interop
GWSzeto Dec 17, 2024
3febf19
merge main
kumaryash90 Jan 13, 2025
624df21
remove deployViaAutoFactoryWithImplementationParams, modify deployVia…
kumaryash90 Jan 14, 2025
da94509
Merge branch 'main' into crosschain-ui
kumaryash90 Jan 14, 2025
fba275c
fix import
kumaryash90 Jan 14, 2025
2b98cc3
auto deploy new clone factory
kumaryash90 Jan 14, 2025
fc59e79
remove hardcoded clone factory address
kumaryash90 Jan 14, 2025
dc427b2
Merge branch 'main' into crosschain-ui
kumaryash90 Jan 14, 2025
9e2c32d
enable crosschain deployments for non-modular prebuilts
kumaryash90 Jan 15, 2025
47dc5ed
Merge branch 'main' into crosschain-ui
kumaryash90 Jan 15, 2025
2936839
enable for direct deploys
kumaryash90 Jan 16, 2025
2d1d7e0
Merge branch 'main' into crosschain-ui
kumaryash90 Jan 16, 2025
92aa723
fix chains
kumaryash90 Jan 16, 2025
3637b38
fix module fetch, disable superchain
kumaryash90 Jan 16, 2025
a68b836
Merge branch 'main' into crosschain-ui
kumaryash90 Jan 16, 2025
1799711
fix event
kumaryash90 Jan 16, 2025
f7dcb41
clean up
kumaryash90 Jan 16, 2025
1cce7fe
update abis
kumaryash90 Jan 17, 2025
436067b
fix salt
kumaryash90 Jan 17, 2025
60728dd
fix condition
kumaryash90 Jan 17, 2025
570c1d4
Merge branch 'main' into crosschain-ui
kumaryash90 Jan 17, 2025
29eaeca
lint
kumaryash90 Jan 17, 2025
198df09
compare addresses lower case
kumaryash90 Jan 17, 2025
dfd2a59
fix old factory check
kumaryash90 Jan 17, 2025
06521a4
remove redundant
kumaryash90 Jan 17, 2025
41dc87f
network selector
kumaryash90 Jan 21, 2025
3207bc7
Merge branch 'main' into crosschain-ui
kumaryash90 Jan 21, 2025
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
2 changes: 1 addition & 1 deletion apps/dashboard/next-env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ export function getContractPageSidebarLinks(data: {
hide: !data.metadata.isModularCore,
exactMatch: true,
},
{
label: "Cross Chain",
href: `${layoutPrefix}/cross-chain`,
exactMatch: true,
},
{
label: "Code Snippets",
href: `${layoutPrefix}/code`,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,329 @@
"use client";

import { Button } from "@/components/ui/button";
import { Form } from "@/components/ui/form";
import {
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { getThirdwebClient } from "@/constants/thirdweb.server";
import { zodResolver } from "@hookform/resolvers/zod";
import {
type ColumnDef,
flexRender,
getCoreRowModel,
useReactTable,
} from "@tanstack/react-table";
import { verifyContract } from "app/(dashboard)/(chain)/[chain_id]/[contractAddress]/sources/ContractSourcesPage";
import {
type DeployModalStep,
DeployStatusModal,
useDeployStatusModal,
} from "components/contract-components/contract-deploy-form/deploy-context-modal";
import {} from "components/contract-components/contract-deploy-form/modular-contract-default-modules-fieldset";
import { useTxNotifications } from "hooks/useTxNotifications";
import Link from "next/link";
import { useState } from "react";
import { useForm } from "react-hook-form";
import {
defineChain,
eth_getCode,
getRpcClient,
prepareTransaction,
sendAndConfirmTransaction,
} from "thirdweb";
import type {
FetchDeployMetadataResult,
ThirdwebContract,
} from "thirdweb/contract";
import {
deployContractfromDeployMetadata,
getOrDeployInfraForPublishedContract,
} from "thirdweb/deploys";
import { useActiveAccount, useSwitchActiveWalletChain } from "thirdweb/react";
import { concatHex, padHex } from "thirdweb/utils";
import { z } from "zod";
import { SingleNetworkSelector } from "./single-network-selector";

type CrossChain = {
id: number;
network: string;
chainId: number;
status: "DEPLOYED" | "NOT_DEPLOYED";
};

const formSchema = z.object({
amounts: z.object({
"84532": z.string(),
"11155420": z.string(),
"919": z.string(),
"111557560": z.string(),
"999999999": z.string(),
"11155111": z.string(),
"421614": z.string(),
}),
Comment on lines +61 to +69
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The chain ID 111557560 appears in the form schema's amounts object but is not present in the topOPStackTestnetChainIds array defined later in the code. To maintain consistency between the form validation and available chains, this chain ID should be removed from the schema.

Spotted by Graphite Reviewer

Is this helpful? React 👍 or 👎 to let us know.

});
type FormSchema = z.output<typeof formSchema>;

export function DataTable({
data,
coreMetadata,
coreContract,
modulesMetadata,
initializeData,
inputSalt,
initCode,
isDirectDeploy,
}: {
data: CrossChain[];
coreMetadata: FetchDeployMetadataResult;
coreContract: ThirdwebContract;
modulesMetadata?: FetchDeployMetadataResult[];
initializeData?: `0x${string}`;
inputSalt?: `0x${string}`;
initCode?: `0x${string}`;
isDirectDeploy: boolean;
}) {
const activeAccount = useActiveAccount();
const switchChain = useSwitchActiveWalletChain();
const deployStatusModal = useDeployStatusModal();
const { onError } = useTxNotifications(
"Successfully deployed contract",
"Failed to deploy contract",
);
const [tableData, setTableData] = useState(data);

const form = useForm<FormSchema>({
resolver: zodResolver(formSchema),
values: {
amounts: {
"84532": "", // Base
"11155420": "", // OP testnet
"919": "", // Mode Network
"111557560": "", // Cyber
"999999999": "", // Zora
"11155111": "", // Sepolia
"421614": "",
},
},
});

const columns: ColumnDef<CrossChain>[] = [
{
accessorKey: "network",
header: "Network",
cell: ({ row }) => {
if (row.getValue("status") === "DEPLOYED") {
return (
<Link
target="_blank"
className="text-blue-500 underline"
href={`/${row.getValue("chainId")}/${coreContract.address}`}
>
{row.getValue("network")}
</Link>
);
}
return row.getValue("network");
},
},
{
accessorKey: "chainId",
header: "Chain ID",
},
{
accessorKey: "status",
header: "Status",
cell: ({ row }) => {
if (row.getValue("status") === "DEPLOYED") {
return <p>Deployed</p>;
}
return (
<Button
type="button"
onClick={() => deployContract(row.getValue("chainId"))}
>
Deploy
</Button>
);
},
},
];

const table = useReactTable({
data: tableData,
columns,
getCoreRowModel: getCoreRowModel(),
});

const deployContract = async (chainId: number) => {
try {
if (!activeAccount) {
throw new Error("No active account");
}

// eslint-disable-next-line no-restricted-syntax
const chain = defineChain(chainId);
const client = getThirdwebClient();
const salt =
inputSalt || concatHex(["0x07", padHex("0x", { size: 31 })]).toString();

await switchChain(chain);

const steps: DeployModalStep[] = [
{
type: "deploy",
signatureCount: 1,
},
];

deployStatusModal.setViewContractLink("");
deployStatusModal.open(steps);

let crosschainContractAddress: string | undefined;
if (initCode && isDirectDeploy) {
const tx = prepareTransaction({
client,
chain,
to: "0x4e59b44847b379578588920cA78FbF26c0B4956C",
data: initCode,
});

await sendAndConfirmTransaction({
transaction: tx,
account: activeAccount,
});

const code = await eth_getCode(
getRpcClient({
client,
chain,
}),
{
address: coreContract.address,
},
);

if (code && code.length > 2) {
crosschainContractAddress = coreContract.address;
}
} else {
crosschainContractAddress = await deployContractfromDeployMetadata({
account: activeAccount,
chain,
client,
deployMetadata: coreMetadata,
isCrosschain: true,
initializeData,
salt,
});

verifyContract({
address: crosschainContractAddress,
chain,
client,
});
if (modulesMetadata) {
for (const m of modulesMetadata) {
await getOrDeployInfraForPublishedContract({
chain,
client,
account: activeAccount,
contractId: m.name,
publisher: m.publisher,
});
}
}
}
deployStatusModal.nextStep();
deployStatusModal.setViewContractLink(
`/${chain.id}/${crosschainContractAddress}`,
);
} catch (e) {
onError(e);
console.error("failed to deploy contract", e);
deployStatusModal.close();
}
};

const handleAddRow = (chain: { chainId: number; name: string }) => {
const existingChain = tableData.find(
(row) => row.chainId === chain.chainId,
);
if (existingChain) {
return;
}

const newRow: CrossChain = {
id: chain.chainId,
network: chain.name,
chainId: chain.chainId,
status: "NOT_DEPLOYED",
};

setTableData((prevData) => [...prevData, newRow]);
};

return (
<Form {...form}>
<form>
<div
style={{
maxHeight: "500px",
overflowY: "auto",
}}
>
<TableContainer>
<Table>
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id}>
{headerGroup.headers.map((header) => {
return (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext(),
)}
</TableHead>
);
})}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(
cell.column.columnDef.cell,
cell.getContext(),
)}
</TableCell>
))}
</TableRow>
))}
</TableBody>
</Table>
<DeployStatusModal deployStatusModal={deployStatusModal} />
</TableContainer>
</div>

<div className="mt-4">
<SingleNetworkSelector onAddRow={handleAddRow} className="w-full" />
</div>
</form>
</Form>
);
}
Loading
Loading