From c89c2e0054002384d8af4e0fb4ce504f0c7496a9 Mon Sep 17 00:00:00 2001 From: joaocosta9 Date: Thu, 13 Nov 2025 19:34:14 +0000 Subject: [PATCH] contract --- .../contract-execution-tabs/index.tsx | 27 ++++---- .../contract-execution-tabs/raw-tab.tsx | 64 +++++++++---------- .../resend-transaction/index.tsx | 6 +- components/contract-execution/shared/types.ts | 18 ++---- .../shared/use-raw-execution.ts | 6 +- stories/contract-functions-list.stories.tsx | 63 ++++++++---------- 6 files changed, 78 insertions(+), 106 deletions(-) diff --git a/components/contract-execution/contract-execution-tabs/index.tsx b/components/contract-execution/contract-execution-tabs/index.tsx index d69b804..4cfa212 100644 --- a/components/contract-execution/contract-execution-tabs/index.tsx +++ b/components/contract-execution/contract-execution-tabs/index.tsx @@ -5,12 +5,12 @@ import { cn } from "../../../lib/utils.js"; import { Accordion } from "../../shadcn/accordion.js"; import { Input } from "../../shadcn/input.js"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "../../shadcn/tabs.js"; -import type { ContractFunctionsListProps } from "../shared/types.js"; +import type { ContractExecutionTabsProps } from "../shared/types.js"; import { FunctionItem } from "./function-item.js"; import { RawOperations } from "./raw-tab.js"; import { SignatureOperations } from "./signature-tab.js"; -export function ContractFunctionsList({ +export function ContractExecutionTabs({ abi, address, chainId, @@ -21,14 +21,13 @@ export function ContractFunctionsList({ onQuery, onWrite, onSimulate, - onRawCall, - onRawTransaction, - enableSignature, + enableRaw = true, + enableSignature = true, addressRenderer, onHashClick, title, NoAbiComponent, -}: ContractFunctionsListProps) { +}: ContractExecutionTabsProps) { const [searchTerm, setSearchTerm] = useState(""); const contractFunctions = useMemo(() => { @@ -53,9 +52,7 @@ export function ContractFunctionsList({ }; }, [contractFunctions, searchTerm]); - const hasRawOperations = onRawCall || onRawTransaction; - const hasSignature = !!enableSignature; - const tabCount = 2 + (hasRawOperations ? 1 : 0) + (hasSignature ? 1 : 0); + const tabCount = 2 + (enableRaw ? 1 : 0) + (enableSignature ? 1 : 0); return (
@@ -101,7 +98,7 @@ export function ContractFunctionsList({ {writeFunctions.length} - {hasRawOperations && ( + {enableRaw && ( )} - {hasSignature && ( + {enableSignature && ( - {hasRawOperations && ( + {enableRaw && ( )} - {hasSignature && ( + {enableSignature && ( Promise<`0x${string}`>; - onRawTransaction?: (params: RawCallParams) => Promise<`0x${string}`>; + onQuery: (params: ExecutionParams) => Promise<`0x${string}`>; + onWrite: (params: ExecutionParams) => Promise<`0x${string}`>; } export function RawOperations({ @@ -30,42 +30,38 @@ export function RawOperations({ addresses, requiresConnection, isConnected, - onRawCall, - onRawTransaction, + onQuery, + onWrite, addressRenderer, onHashClick, }: RawOperationsProps) { return (
- {onRawCall && ( - - )} - {onRawTransaction && ( - - )} + +
); @@ -73,7 +69,7 @@ export function RawOperations({ interface RawOperationItemProps extends BaseExecutionProps { type: "call" | "transaction"; - onExecute: (params: RawCallParams) => Promise<`0x${string}`>; + onExecute: (params: ExecutionParams) => Promise<`0x${string}`>; } function RawOperationItem({ diff --git a/components/contract-execution/resend-transaction/index.tsx b/components/contract-execution/resend-transaction/index.tsx index f8f4495..ed2d63f 100644 --- a/components/contract-execution/resend-transaction/index.tsx +++ b/components/contract-execution/resend-transaction/index.tsx @@ -10,7 +10,7 @@ import { MsgSenderInput, } from "../shared/components.js"; import { useMsgSenderForm } from "../shared/form-utils.js"; -import type { ExecutionParams, RawCallParams } from "../shared/types.js"; +import type { ExecutionParams } from "../shared/types.js"; import { useFunctionExecution } from "../shared/use-function-execution.js"; import { useRawExecution } from "../shared/use-raw-execution.js"; import { isWriteFunction } from "../shared/utils.js"; @@ -28,7 +28,6 @@ export interface ResendTransactionProps { onQuery: (params: ExecutionParams) => Promise; onWrite: (params: ExecutionParams) => Promise; onSimulate?: (params: ExecutionParams) => Promise; - onRawTransaction?: (params: RawCallParams) => Promise; addressRenderer?: (address: Address) => React.ReactNode; onHashClick?: (hash: string) => void; } @@ -46,7 +45,6 @@ export function ResendTransaction({ onQuery, onWrite, onSimulate, - onRawTransaction, addressRenderer, onHashClick, }: ResendTransactionProps) { @@ -73,7 +71,7 @@ export function ResendTransaction({ const functionExecution = useFunctionExecution(); const rawExecution = useRawExecution({ isWrite: true, - onExecute: onRawTransaction || (async () => "0x" as Hex), + onExecute: onWrite, }); const handleSimulate = () => { diff --git a/components/contract-execution/shared/types.ts b/components/contract-execution/shared/types.ts index 8c962b2..ba2e294 100644 --- a/components/contract-execution/shared/types.ts +++ b/components/contract-execution/shared/types.ts @@ -13,19 +13,13 @@ export interface BaseExecutionProps { } export interface ExecutionParams { - abiFunction: AbiFunction; + abiFunction?: AbiFunction; callData: Hex; msgSender?: Address; value?: bigint; } -export interface RawCallParams { - data: Hex; - value?: bigint; - msgSender?: Address; -} - -export interface ContractFunctionsListProps { +export interface ContractExecutionTabsProps { /** Full contract ABI (will be filtered internally for functions) */ abi: Abi; /** Contract address */ @@ -46,11 +40,9 @@ export interface ContractFunctionsListProps { onWrite: (params: ExecutionParams) => Promise<`0x${string}`>; /** Optional simulate function for write functions - returns raw hex result from simulation */ onSimulate?: (params: ExecutionParams) => Promise<`0x${string}`>; - /** Optional raw call function (eth_call with arbitrary data) - returns raw hex result */ - onRawCall?: (params: RawCallParams) => Promise<`0x${string}`>; - /** Optional raw transaction function (send transaction with arbitrary data) - returns transaction hash */ - onRawTransaction?: (params: RawCallParams) => Promise<`0x${string}`>; - /** Enable signature-based interaction tab */ + /** Enable raw call/transaction tab (default: true) */ + enableRaw?: boolean; + /** Enable signature-based interaction tab (default: true) */ enableSignature?: boolean; /** Custom address renderer for form inputs */ addressRenderer?: (address: Address) => React.ReactNode; diff --git a/components/contract-execution/shared/use-raw-execution.ts b/components/contract-execution/shared/use-raw-execution.ts index 82d6332..7f8fe0a 100644 --- a/components/contract-execution/shared/use-raw-execution.ts +++ b/components/contract-execution/shared/use-raw-execution.ts @@ -1,11 +1,11 @@ import { useState } from "react"; import type { Address, Hex } from "viem"; -import type { RawCallParams } from "./types.js"; +import type { ExecutionParams } from "./types.js"; import type { InternalResult } from "./use-function-execution.js"; interface UseRawExecutionParams { isWrite: boolean; - onExecute: (params: RawCallParams) => Promise; + onExecute: (params: ExecutionParams) => Promise; } export function useRawExecution({ isWrite, onExecute }: UseRawExecutionParams) { @@ -22,7 +22,7 @@ export function useRawExecution({ isWrite, onExecute }: UseRawExecutionParams) { setIsExecuting(true); try { const response = await onExecute({ - data: params.callData as Hex, + callData: params.callData as Hex, value: params.value, msgSender: params.msgSender, }); diff --git a/stories/contract-functions-list.stories.tsx b/stories/contract-functions-list.stories.tsx index 25924f1..6823945 100644 --- a/stories/contract-functions-list.stories.tsx +++ b/stories/contract-functions-list.stories.tsx @@ -1,16 +1,13 @@ import type { Meta, StoryObj } from "@storybook/react-vite"; import React, { useState } from "react"; import type { Abi } from "viem"; -import { ContractFunctionsList } from "../components/contract-execution/contract-execution-tabs/index.js"; -import type { - ExecutionParams, - RawCallParams, -} from "../components/contract-execution/shared/types.js"; +import { ContractExecutionTabs } from "../components/contract-execution/contract-execution-tabs/index.js"; +import type { ExecutionParams } from "../components/contract-execution/shared/types.js"; import { Button } from "../components/shadcn/button.js"; -const meta: Meta = { - title: "ethui/ContractFunctionsList", - component: ContractFunctionsList, +const meta: Meta = { + title: "ethui/ContractExecutionTabs", + component: ContractExecutionTabs, parameters: { layout: "padded", }, @@ -111,6 +108,11 @@ const mockQuery = async (params: ExecutionParams): Promise<`0x${string}`> => { // Simulate async operation await new Promise((resolve) => setTimeout(resolve, 1000)); + // If no abiFunction (raw call), return generic result + if (!params.abiFunction) { + return "0x0000000000000000000000000000000000000000000000000000000000000001"; + } + // Mock encoded result for read operations (manually encoded for simplicity) const mockResults: Record = { balanceOf: @@ -147,6 +149,11 @@ const mockSimulate = async ( // Simulate async operation await new Promise((resolve) => setTimeout(resolve, 800)); + // If no abiFunction, can't simulate + if (!params.abiFunction) { + return "0x0000000000000000000000000000000000000000000000000000000000000001"; + } + const isWrite = params.abiFunction.stateMutability !== "view" && params.abiFunction.stateMutability !== "pure"; @@ -160,23 +167,6 @@ const mockSimulate = async ( } }; -// Mock raw operation handlers -const mockRawCall = async (params: RawCallParams): Promise<`0x${string}`> => { - console.log("Raw call with:", params); - await new Promise((resolve) => setTimeout(resolve, 1000)); - // Return mock raw hex result - return "0x0000000000000000000000000000000000000000000000000000000000000001"; -}; - -const mockRawTransaction = async ( - params: RawCallParams, -): Promise<`0x${string}`> => { - console.log("Raw transaction with:", params); - await new Promise((resolve) => setTimeout(resolve, 1000)); - // Return mock transaction hash - return "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"; -}; - // Story: Basic usage with all features export const Default: Story = { args: { @@ -190,8 +180,7 @@ export const Default: Story = { onQuery: mockQuery, onWrite: mockWrite, onSimulate: mockSimulate, - onRawCall: mockRawCall, - onRawTransaction: mockRawTransaction, + enableRaw: true, enableSignature: true, }, }; @@ -208,7 +197,9 @@ export const WithoutSimulateAndRaw: Story = { isConnected: true, onQuery: mockQuery, onWrite: mockWrite, - // No onSimulate, onRawCall, or onRawTransaction - shows only Read/Write tabs + // No onSimulate or raw tabs + enableRaw: false, + enableSignature: false, }, }; @@ -228,7 +219,7 @@ function InteractiveStory() {
- ); @@ -272,8 +263,8 @@ export const WithError: Story = { onQuery: mockQuery, onWrite: mockWriteWithError, onSimulate: mockSimulate, - onRawCall: mockRawCall, - onRawTransaction: mockRawTransaction, + enableRaw: true, + enableSignature: true, }, }; @@ -290,8 +281,7 @@ export const EmptyAbi: Story = { onQuery: mockQuery, onWrite: mockWrite, onSimulate: mockSimulate, - onRawCall: mockRawCall, - onRawTransaction: mockRawTransaction, + enableRaw: true, enableSignature: true, }, }; @@ -324,8 +314,7 @@ export const EmptyAbiWithCustomComponent: Story = { onQuery: mockQuery, onWrite: mockWrite, onSimulate: mockSimulate, - onRawCall: mockRawCall, - onRawTransaction: mockRawTransaction, + enableRaw: true, enableSignature: true, NoAbiComponent: CustomNoAbi, },