diff --git a/components/contract-execution/components/shared-components.tsx b/components/contract-execution/components/shared-components.tsx
deleted file mode 100644
index 46a64ff..0000000
--- a/components/contract-execution/components/shared-components.tsx
+++ /dev/null
@@ -1,86 +0,0 @@
-import { Info } from "lucide-react";
-import { Form } from "../../form/index.js";
-import { Alert, AlertDescription, AlertTitle } from "../../shadcn/alert.js";
-import { Button } from "../../shadcn/button.js";
-
-export function MsgSenderInput() {
- return (
-
-
Msg Sender (Optional)
- }
- placeholder="0x..."
- className="w-full"
- />
-
- );
-}
-
-export function ConnectWalletAlert() {
- return (
-
-
- Connect your wallet
-
- Connect your wallet to execute this write function
-
-
- );
-}
-
-interface ActionButtonsProps {
- isWrite: boolean;
- callData: string | undefined;
- isSimulating: boolean;
- isExecuting: boolean;
- isConnected: boolean;
- hasSimulate: boolean;
- simulate?: () => void;
- execute: () => void;
-}
-
-export function ActionButtons({
- isWrite,
- callData,
- isSimulating,
- isExecuting,
- isConnected,
- hasSimulate,
- simulate,
- execute,
-}: ActionButtonsProps) {
- return (
-
- {isWrite ? (
- <>
- {hasSimulate && (
-
- )}
-
- >
- ) : (
-
- )}
-
- );
-}
diff --git a/components/contract-execution/components/function-item.tsx b/components/contract-execution/contract-execution-tabs/function-item.tsx
similarity index 71%
rename from components/contract-execution/components/function-item.tsx
rename to components/contract-execution/contract-execution-tabs/function-item.tsx
index f3281b6..75be755 100644
--- a/components/contract-execution/components/function-item.tsx
+++ b/components/contract-execution/contract-execution-tabs/function-item.tsx
@@ -1,52 +1,29 @@
-import { zodResolver } from "@hookform/resolvers/zod";
import { memo, useCallback, useState } from "react";
-import { FormProvider, useForm } from "react-hook-form";
-import type { AbiFunction, Address } from "viem";
-import { isAddress } from "viem";
-import { z } from "zod";
+import { FormProvider } from "react-hook-form";
+import type { AbiFunction } from "viem";
import { AbiItemFormWithPreview } from "../../abi-form/abi-item-form-with-preview.js";
-import type { AddressData } from "../../address-autocomplete-input.js";
import {
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "../../shadcn/accordion.js";
-import type { ExecutionParams } from "../types.js";
-import { useFunctionExecution } from "../use-function-execution.js";
-import { DefaultResultDisplay } from "./result-display.js";
import {
ActionButtons,
ConnectWalletAlert,
+ DefaultResultDisplay,
MsgSenderInput,
-} from "./shared-components.js";
+} from "../shared/components.js";
+import { useMsgSenderForm } from "../shared/form-utils.js";
+import type { BaseExecutionProps, ExecutionParams } from "../shared/types.js";
+import { useFunctionExecution } from "../shared/use-function-execution.js";
+import { isWriteFunction } from "../shared/utils.js";
-const executionFormSchema = z.object({
- msgSender: z
- .string()
- .refine(
- (val) => {
- if (!val) return true;
- return isAddress(val);
- },
- { message: "Invalid address format" },
- )
- .optional(),
-});
-
-interface FunctionItemProps {
+interface FunctionItemProps extends BaseExecutionProps {
func: AbiFunction;
index: number;
- address: Address;
- chainId: number;
- sender?: Address;
- addresses?: AddressData[];
- requiresConnection: boolean;
- isConnected: boolean;
onQuery: (params: ExecutionParams) => Promise<`0x${string}`>;
onWrite: (params: ExecutionParams) => Promise<`0x${string}`>;
onSimulate?: (params: ExecutionParams) => Promise<`0x${string}`>;
- addressRenderer?: (address: Address) => React.ReactNode;
- onHashClick?: (hash: string) => void;
}
export const FunctionItem = memo(
@@ -68,19 +45,9 @@ export const FunctionItem = memo(
const [callData, setCallData] = useState("");
const { result, isSimulating, isExecuting, simulate, execute } =
useFunctionExecution();
+ const { form, msgSender } = useMsgSenderForm(sender);
- const form = useForm({
- mode: "onChange",
- resolver: zodResolver(executionFormSchema),
- defaultValues: {
- msgSender: "",
- },
- });
-
- const msgSender = form.watch().msgSender || "";
-
- const isWrite =
- func.stateMutability !== "view" && func.stateMutability !== "pure";
+ const isWrite = isWriteFunction(func);
const handleCallDataChange = useCallback(
(newCallData: string | undefined) => {
@@ -93,7 +60,7 @@ export const FunctionItem = memo(
simulate({
abiFunction: func,
callData,
- msgSender: msgSender ? (msgSender as Address) : undefined,
+ msgSender,
onQuery,
onWrite,
onSimulate,
@@ -104,7 +71,7 @@ export const FunctionItem = memo(
execute({
abiFunction: func,
callData,
- msgSender: msgSender ? (msgSender as Address) : undefined,
+ msgSender,
onQuery,
onWrite,
onSimulate,
@@ -128,10 +95,6 @@ export const FunctionItem = memo(
{isWrite &&
}
- {isWrite && requiresConnection && !isConnected && (
-
- )}
-
+ {isWrite && requiresConnection && !isConnected && (
+
+ )}
+
{
- if (!val) return true;
- return isAddress(val);
- },
- { message: "Invalid address format" },
- )
- .optional(),
-});
-
-interface RawOperationsProps {
- address: Address;
- chainId: number;
- sender?: Address;
- addresses?: AddressData[];
- requiresConnection: boolean;
- isConnected: boolean;
+import {
+ ConnectWalletAlert,
+ DefaultResultDisplay,
+ MsgSenderInput,
+} from "../shared/components.js";
+import { useMsgSenderForm } from "../shared/form-utils.js";
+import type { BaseExecutionProps, RawCallParams } from "../shared/types.js";
+import { useRawExecution } from "../shared/use-raw-execution.js";
+
+interface RawOperationsProps extends BaseExecutionProps {
onRawCall?: (params: RawCallParams) => Promise<`0x${string}`>;
onRawTransaction?: (params: RawCallParams) => Promise<`0x${string}`>;
- addressRenderer?: (address: Address) => React.ReactNode;
- onHashClick?: (hash: string) => void;
}
export function RawOperations({
@@ -99,17 +71,9 @@ export function RawOperations({
);
}
-interface RawOperationItemProps {
+interface RawOperationItemProps extends BaseExecutionProps {
type: "call" | "transaction";
- address: Address;
- chainId: number;
- sender?: Address;
- addresses?: AddressData[];
- requiresConnection: boolean;
- isConnected: boolean;
onExecute: (params: RawCallParams) => Promise<`0x${string}`>;
- addressRenderer?: (address: Address) => React.ReactNode;
- onHashClick?: (hash: string) => void;
}
function RawOperationItem({
@@ -126,20 +90,17 @@ function RawOperationItem({
}: RawOperationItemProps) {
const [callData, setCallData] = useState("");
const [value, setValue] = useState();
- const [result, setResult] = useState(null);
- const [isExecuting, setIsExecuting] = useState(false);
-
- const form = useForm({
- mode: "onChange",
- resolver: zodResolver(executionFormSchema),
- defaultValues: {
- msgSender: "",
- },
- });
-
- const msgSender = form.watch().msgSender || "";
+ const { form, msgSender } = useMsgSenderForm(sender);
const isWrite = type === "transaction";
+ const {
+ result,
+ isExecuting,
+ execute: executeRaw,
+ } = useRawExecution({
+ isWrite,
+ onExecute,
+ });
const title = type === "call" ? "Raw Call" : "Raw Transaction";
const description =
type === "call"
@@ -147,44 +108,15 @@ function RawOperationItem({
: "Send transaction with arbitrary calldata";
const handleCallDataChange = useCallback(
- ({ data, value: newValue }: { data?: `0x${string}`; value?: bigint }) => {
+ ({ data, value: newValue }: { data?: Hex; value?: bigint }) => {
setCallData(data || "");
setValue(newValue);
},
[],
);
- const handleExecute = async () => {
- if (!callData) return;
- setIsExecuting(true);
- try {
- const result = await onExecute({
- data: callData as `0x${string}`,
- value,
- msgSender: msgSender ? (msgSender as Address) : undefined,
- });
-
- if (isWrite) {
- setResult({
- type: "execution",
- hash: result,
- cleanResult: "Transaction submitted",
- });
- } else {
- setResult({
- type: "call",
- data: result,
- cleanResult: result,
- });
- }
- } catch (error) {
- setResult({
- type: "error",
- error: error instanceof Error ? error.message : "Unknown error",
- });
- } finally {
- setIsExecuting(false);
- }
+ const handleExecute = () => {
+ executeRaw({ callData, value, msgSender });
};
return (
@@ -203,10 +135,6 @@ function RawOperationItem({
{isWrite &&
}
- {isWrite && requiresConnection && !isConnected && (
-
- )}
-
+ {isWrite && requiresConnection && !isConnected && (
+
+ )}
+