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 25 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
Commits
Show all changes
25 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
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
Prev Previous commit
Next Next commit
implemented cross chain transfers
  • Loading branch information
GWSzeto committed Dec 17, 2024
commit ec1a0a1bfa6e025baca350bcf8a38e59d2d1dc9d
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
"use client";

import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import {
Form,
FormControl,
FormField,
FormItem,
FormMessage,
} from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import {
Table,
TableBody,
Expand All @@ -12,6 +19,8 @@ import {
TableRow,
} from "@/components/ui/table";
import { getThirdwebClient } from "@/constants/thirdweb.server";
import { zodResolver } from "@hookform/resolvers/zod";
import { useMutation } from "@tanstack/react-query";
import {
type ColumnDef,
flexRender,
Expand All @@ -32,13 +41,16 @@ import {
} from "components/contract-components/contract-deploy-form/modular-contract-default-modules-fieldset";
import { useTxNotifications } from "hooks/useTxNotifications";
import Link from "next/link";
import { useForm } from "react-hook-form";
import {
ZERO_ADDRESS,
defineChain,
eth_getTransactionCount,
getContract,
getRpcClient,
prepareContractCall,
readContract,
sendAndConfirmTransaction,
sendTransaction,
waitForReceipt,
} from "thirdweb";
Expand All @@ -55,6 +67,7 @@ import {
encodeAbiParameters,
padHex,
} from "thirdweb/utils";
import { z } from "zod";

type CrossChain = {
id: number;
Expand All @@ -63,6 +76,22 @@ type CrossChain = {
status: "DEPLOYED" | "NOT_DEPLOYED";
};

type ChainId = "84532" | "11155420" | "919" | "111557560" | "999999999";

const formSchema = z.object({
amounts: z.object({
"84532": z.string(),
"11155420": z.string(),
"919": z.string(),
"111557560": z.string(),
"999999999": z.string(),
}),
});
type FormSchema = z.output<typeof formSchema>;

const positiveIntegerRegex = /^[0-9]\d*$/;
const superchainBridgeAddress = "0x4200000000000000000000000000000000000028";

export function DataTable({
data,
coreMetadata,
Expand All @@ -84,6 +113,64 @@ export function DataTable({
"Failed to deploy contract",
);

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

const crossChainTransfer = async (chainId: ChainId) => {
if (!activeAccount) {
throw new Error("Account not connected");
}
const amount = form.getValues().amounts[chainId];
if (!positiveIntegerRegex.test(amount)) {
form.setError(`amounts.${chainId}`, { message: "Invalid Amount" });
return;
}

const superChainBridge = getContract({
address: superchainBridgeAddress,
chain: coreContract.chain,
client: coreContract.client,
});

const sendErc20Tx = prepareContractCall({
contract: superChainBridge,
method:
"function sendERC20(address _token, address _to, uint256 _amount, uint256 _chainId)",
params: [
coreContract.address,
activeAccount.address,
BigInt(amount),
BigInt(chainId),
],
});

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

const crossChainTransferNotifications = useTxNotifications(
"Successfully submitted cross chain transfer",
"Failed to submit cross chain transfer",
);

const crossChainTransferMutation = useMutation({
mutationFn: crossChainTransfer,
onSuccess: crossChainTransferNotifications.onSuccess,
onError: crossChainTransferNotifications.onError,
});

const columns: ColumnDef<CrossChain>[] = [
{
accessorKey: "network",
Expand Down Expand Up @@ -112,10 +199,40 @@ export function DataTable({
header: "Status",
cell: ({ row }) => {
if (row.getValue("status") === "DEPLOYED") {
return <Badge variant="success">Deployed</Badge>;
return (
<FormField
disabled // TODO: undo once the OP interop upgrade goes through
control={form.control}
name={`amounts.${row.getValue("chainId") as ChainId}`}
render={({ field }) => (
<FormItem>
<FormControl>
<div className="flex">
<Input className="rounded-r-0 border-r-none" {...field} />
<Button
type="button"
onClick={() =>
crossChainTransferMutation.mutate(
row.getValue("chainId"),
)
}
className="rounded-lg rounded-r-0 border border-r-none"
>
Transfer
</Button>
</div>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
);
}
return (
<Button onClick={() => deployContract(row.getValue("chainId"))}>
<Button
type="button"
onClick={() => deployContract(row.getValue("chainId"))}
>
Deploy
</Button>
);
Expand Down Expand Up @@ -250,8 +367,6 @@ export function DataTable({
);
}

console.log("nonce used: ", currentNonce + i);

const installTransaction = installPublishedModule({
contract,
account: activeAccount,
Expand Down Expand Up @@ -285,42 +400,49 @@ export function DataTable({
};

return (
<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>
<Form {...form}>
<form>
<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>
))}
</TableRow>
))}
</TableBody>
</Table>
<DeployStatusModal deployStatusModal={deployStatusModal} />
</TableContainer>
</TableBody>
</Table>
<DeployStatusModal deployStatusModal={deployStatusModal} />
</TableContainer>
</form>
</Form>
);
}