1- import { encodeFunctionData , isAddress , type Abi , type Address } from "viem" ;
1+ import { createPublicClient , encodeFunctionData , http , isAddress , type Abi , type AbiFunction , type Address } from "viem" ;
22import { buildExplorerUrl } from "../utils/explorer.js" ;
33import { assertToolCapability } from "./capability-guard.js" ;
44import { resolveToolNetworkConfig } from "./network.js" ;
55import type { ToolHandler } from "./types.js" ;
66
7+ function isViewOrPure ( abi : Abi , functionName : string ) : boolean {
8+ const fn = abi . find (
9+ ( item ) : item is AbiFunction =>
10+ item . type === "function" && item . name === functionName ,
11+ ) ;
12+ return fn ?. stateMutability === "view" || fn ?. stateMutability === "pure" ;
13+ }
14+
715function assertAddress ( value : unknown , field : string ) : Address {
816 if ( typeof value !== "string" || ! isAddress ( value ) ) {
917 throw new Error ( `${ field } must be a valid 0x-prefixed address` ) ;
@@ -80,16 +88,39 @@ export const writeContractTool: ToolHandler = {
8088 throw new Error ( "invalid abi/functionName/args payload" ) ;
8189 }
8290
83- const status = context . sessionManager . getSessionStatus ( ) ;
84- if ( status !== "active" ) {
85- throw new Error ( `session must be active (current status: ${ status } )` ) ;
86- }
87-
8891 const session = context . sessionManager . getSession ( ) ;
8992 if ( ! session ) {
9093 throw new Error ( "session is missing" ) ;
9194 }
9295
96+ const networkConfig = resolveToolNetworkConfig ( context , session . chainId ) ;
97+
98+ if ( isViewOrPure ( abi , functionName ) ) {
99+ const publicClient = createPublicClient ( {
100+ chain : networkConfig . chain ,
101+ transport : http ( networkConfig . rpcUrl ) ,
102+ } ) ;
103+
104+ const result = await publicClient . readContract ( {
105+ address,
106+ abi,
107+ functionName,
108+ args,
109+ } as never ) ;
110+
111+ return {
112+ result,
113+ accountAddress : session . accountAddress ,
114+ chainId : session . chainId ,
115+ contract : { address, functionName, args : args ?? [ ] } ,
116+ } ;
117+ }
118+
119+ const status = context . sessionManager . getSessionStatus ( ) ;
120+ if ( status !== "active" ) {
121+ throw new Error ( `session must be active (current status: ${ status } )` ) ;
122+ }
123+
93124 const abstractClient = await context . sessionManager . getAbstractClient ( ) ;
94125 const txHash = await abstractClient . writeContract ( {
95126 address,
@@ -99,7 +130,6 @@ export const writeContractTool: ToolHandler = {
99130 value,
100131 } as never ) ;
101132
102- const networkConfig = resolveToolNetworkConfig ( context , session . chainId ) ;
103133 const explorerBase = networkConfig . chain . blockExplorers ?. default ?. url ?? null ;
104134
105135 return {
0 commit comments