diff --git a/examples/README.md b/examples/README.md
index b639fbb..9df2e80 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -18,7 +18,7 @@ The `examples/` directory is a growing & living folder, and open for contributio
- [ ] Multicall
- [ ] Call
- [ ] Events
- - [ ] Simulating Method Calls
+ - [x] Simulating Method Calls
- Filters & Logs
- [ ] Blocks
- [ ] Pending Transactions
diff --git a/examples/contracts_simulating_contract/README.md b/examples/contracts_simulating_contract/README.md
new file mode 100644
index 0000000..40b68e7
--- /dev/null
+++ b/examples/contracts_simulating_contract/README.md
@@ -0,0 +1,3 @@
+# simulating contract Example
+
+[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github.com/iosh/cive/tree/main/examples/contracts_simulating_contract)
\ No newline at end of file
diff --git a/examples/contracts_simulating_contract/index.html b/examples/contracts_simulating_contract/index.html
new file mode 100644
index 0000000..dfdcee0
--- /dev/null
+++ b/examples/contracts_simulating_contract/index.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ simulating contract Example
+ Loading...
+
+
+
diff --git a/examples/contracts_simulating_contract/index.tsx b/examples/contracts_simulating_contract/index.tsx
new file mode 100644
index 0000000..41de479
--- /dev/null
+++ b/examples/contracts_simulating_contract/index.tsx
@@ -0,0 +1,9 @@
+import React from 'react'
+import ReactDOM from 'react-dom/client'
+import App from './src/App'
+import 'bulma/css/bulma.css'
+ReactDOM.createRoot(document.getElementById('app') as HTMLElement).render(
+
+
+ ,
+)
diff --git a/examples/contracts_simulating_contract/package.json b/examples/contracts_simulating_contract/package.json
new file mode 100644
index 0000000..bf3f841
--- /dev/null
+++ b/examples/contracts_simulating_contract/package.json
@@ -0,0 +1,21 @@
+{
+ "name": "contracts_simulating_contract",
+ "private": true,
+ "type": "module",
+ "scripts": {
+ "dev": "vite"
+ },
+ "dependencies": {
+ "bulma": "^1.0.2",
+ "cive": "latest",
+ "react": "^18.3.1",
+ "react-dom": "^18.3.1"
+ },
+ "devDependencies": {
+ "@types/react": "^18.3.8",
+ "@types/react-dom": "^18.3.0",
+ "@vitejs/plugin-react": "^4.3.1",
+ "typescript": "^5.6.2",
+ "vite": "^5.4.4"
+ }
+}
diff --git a/examples/contracts_simulating_contract/src/App.tsx b/examples/contracts_simulating_contract/src/App.tsx
new file mode 100644
index 0000000..eff2b0c
--- /dev/null
+++ b/examples/contracts_simulating_contract/src/App.tsx
@@ -0,0 +1,192 @@
+import {
+ http,
+ type Address,
+ type Hash,
+ type SimulateContractErrorType,
+ type SimulateContractReturnType,
+ type WaitForTransactionReceiptErrorType,
+ type WaitForTransactionReceiptReturnType,
+ createPublicClient,
+ createWalletClient,
+ custom,
+ parseUnits,
+} from 'cive'
+import { mainnet, testnet } from 'cive/chains'
+import { useCallback, useState } from 'react'
+import 'cive/window'
+import contract from './contract'
+
+const CONTRACT_ADDRESS = 'cfxtest:acfrcwu7yn4ysjybux326my6a743zw2zwjps5had1g'
+
+const client = createPublicClient({
+ chain: testnet,
+ transport: http(),
+})
+const walletClient = createWalletClient({
+ chain: testnet,
+ transport: custom(window.fluent!),
+})
+export default function App() {
+ const [account, setAccount] = useState()
+ const [mint, setMint] =
+ useState<
+ SimulateContractReturnType<
+ (typeof contract)['abi'],
+ 'mint',
+ [Address, bigint]
+ >
+ >()
+ const [approve, setApprove] =
+ useState<
+ SimulateContractReturnType<
+ (typeof contract)['abi'],
+ 'approve',
+ [Address, bigint]
+ >
+ >()
+ const [error, setError] = useState()
+
+ const connect = useCallback(async () => {
+ const [address] = await walletClient.requestAddresses()
+ setAccount(address)
+ }, [])
+
+ const handleSimulateMint = useCallback(async () => {
+ setError('')
+ if (!account) return
+ try {
+ const result = await client.simulateContract({
+ account,
+ address: CONTRACT_ADDRESS,
+ abi: contract.abi,
+ functionName: 'mint',
+ args: [account, parseUnits('1', 18)],
+ })
+ setMint(result)
+ } catch (e: unknown) {
+ const err = e as SimulateContractErrorType
+
+ setError(err.name)
+ }
+ }, [account])
+
+ const handleSimulateApprove = useCallback(async () => {
+ setError('')
+ if (!account) return
+ try {
+ const result = await client.simulateContract({
+ account,
+ address: CONTRACT_ADDRESS,
+ abi: contract.abi,
+ functionName: 'approve',
+ args: [account, parseUnits('1', 18)],
+ })
+ setApprove(result)
+ } catch (e: unknown) {
+ const err = e as SimulateContractErrorType
+ setError(err.name)
+ }
+ }, [account])
+ return (
+
+
+ {account ? (
+
+
Account: {account}
+
+
+
+
Result: {`${mint?.result}`}
+
+ {mint?.request && (
+
+
Simulate Mint request:
+
+
+
+ # |
+ Key |
+ Value |
+
+
+
+ {mint?.request &&
+ Object.entries(mint?.request).map(
+ ([key, value], idx) => (
+
+ {idx} |
+ {key} |
+ {`${value}`} |
+
+ ),
+ )}
+
+
+
+ )}
+
+
+
+
+
+
+
+
+ Result: {`${approve?.result}`}
+
+
+ you can use the simulateContract to get the contract's return
+ value
+
+
+ {approve?.request && (
+
+
Simulate Approve request:
+
+
+
+ # |
+ Key |
+ Value |
+
+
+
+ {approve?.request &&
+ Object.entries(approve?.request).map(
+ ([key, value], idx) => (
+
+ {idx} |
+ {key} |
+ {`${value}`} |
+
+ ),
+ )}
+
+
+
+ you can use the request to call writeContract function
+
+
+ )}
+
+
+
+ {error && (
+
+ )}
+
+ ) : (
+
+ )}
+
+
+ )
+}
diff --git a/examples/contracts_simulating_contract/src/contract.ts b/examples/contracts_simulating_contract/src/contract.ts
new file mode 100644
index 0000000..deb692d
--- /dev/null
+++ b/examples/contracts_simulating_contract/src/contract.ts
@@ -0,0 +1,240 @@
+export default {
+ abi: [
+ { inputs: [], stateMutability: 'nonpayable', type: 'constructor' },
+ {
+ inputs: [
+ { internalType: 'address', name: 'spender', type: 'address' },
+ { internalType: 'uint256', name: 'allowance', type: 'uint256' },
+ { internalType: 'uint256', name: 'needed', type: 'uint256' },
+ ],
+ name: 'ERC20InsufficientAllowance',
+ type: 'error',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'sender', type: 'address' },
+ { internalType: 'uint256', name: 'balance', type: 'uint256' },
+ { internalType: 'uint256', name: 'needed', type: 'uint256' },
+ ],
+ name: 'ERC20InsufficientBalance',
+ type: 'error',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'approver', type: 'address' }],
+ name: 'ERC20InvalidApprover',
+ type: 'error',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'receiver', type: 'address' }],
+ name: 'ERC20InvalidReceiver',
+ type: 'error',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'sender', type: 'address' }],
+ name: 'ERC20InvalidSender',
+ type: 'error',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'spender', type: 'address' }],
+ name: 'ERC20InvalidSpender',
+ type: 'error',
+ },
+ { inputs: [], name: 'EnforcedPause', type: 'error' },
+ { inputs: [], name: 'ExpectedPause', type: 'error' },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'owner',
+ type: 'address',
+ },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'spender',
+ type: 'address',
+ },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'value',
+ type: 'uint256',
+ },
+ ],
+ name: 'Approval',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'address',
+ name: 'account',
+ type: 'address',
+ },
+ ],
+ name: 'Paused',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ internalType: 'address',
+ name: 'from',
+ type: 'address',
+ },
+ { indexed: true, internalType: 'address', name: 'to', type: 'address' },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: 'value',
+ type: 'uint256',
+ },
+ ],
+ name: 'Transfer',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: false,
+ internalType: 'address',
+ name: 'account',
+ type: 'address',
+ },
+ ],
+ name: 'Unpaused',
+ type: 'event',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'owner', type: 'address' },
+ { internalType: 'address', name: 'spender', type: 'address' },
+ ],
+ name: 'allowance',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'spender', type: 'address' },
+ { internalType: 'uint256', name: 'value', type: 'uint256' },
+ ],
+ name: 'approve',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'account', type: 'address' }],
+ name: 'balanceOf',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'uint256', name: 'value', type: 'uint256' }],
+ name: 'burn',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'account', type: 'address' },
+ { internalType: 'uint256', name: 'value', type: 'uint256' },
+ ],
+ name: 'burnFrom',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'decimals',
+ outputs: [{ internalType: 'uint8', name: '', type: 'uint8' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'to', type: 'address' },
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ ],
+ name: 'mint',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'name',
+ outputs: [{ internalType: 'string', name: '', type: 'string' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'pause',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'paused',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'symbol',
+ outputs: [{ internalType: 'string', name: '', type: 'string' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'totalSupply',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'to', type: 'address' },
+ { internalType: 'uint256', name: 'value', type: 'uint256' },
+ ],
+ name: 'transfer',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'from', type: 'address' },
+ { internalType: 'address', name: 'to', type: 'address' },
+ { internalType: 'uint256', name: 'value', type: 'uint256' },
+ ],
+ name: 'transferFrom',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'unpause',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ ],
+} as const
diff --git a/examples/contracts_simulating_contract/tsconfig.json b/examples/contracts_simulating_contract/tsconfig.json
new file mode 100644
index 0000000..f0a2350
--- /dev/null
+++ b/examples/contracts_simulating_contract/tsconfig.json
@@ -0,0 +1,24 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "useDefineForClassFields": true,
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
+ "module": "ESNext",
+ "skipLibCheck": true,
+
+ /* Bundler mode */
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "isolatedModules": true,
+ "moduleDetection": "force",
+ "noEmit": true,
+ "jsx": "react-jsx",
+
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "include": ["src"]
+}
diff --git a/examples/contracts_simulating_contract/vite.config.ts b/examples/contracts_simulating_contract/vite.config.ts
new file mode 100644
index 0000000..36f7f4e
--- /dev/null
+++ b/examples/contracts_simulating_contract/vite.config.ts
@@ -0,0 +1,7 @@
+import react from '@vitejs/plugin-react'
+import { defineConfig } from 'vite'
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ plugins: [react()],
+})
diff --git a/examples/contracts_writing_contract/src/App.tsx b/examples/contracts_writing_contract/src/App.tsx
index fcfdc20..867ed83 100644
--- a/examples/contracts_writing_contract/src/App.tsx
+++ b/examples/contracts_writing_contract/src/App.tsx
@@ -1,13 +1,13 @@
import {
http,
+ type Address,
+ type Hash,
+ type SimulateContractErrorType,
+ type WaitForTransactionReceiptErrorType,
+ type WaitForTransactionReceiptReturnType,
createPublicClient,
createWalletClient,
custom,
- Address,
- Hash,
- WaitForTransactionReceiptReturnType,
- WaitForTransactionReceiptErrorType,
- SimulateContractErrorType,
} from 'cive'
import { mainnet, testnet } from 'cive/chains'
import { useCallback, useState } from 'react'
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 1988bbe..eda896c 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -233,6 +233,37 @@ importers:
specifier: ^5.4.4
version: 5.4.4(@types/node@20.14.10)
+ examples/contracts_simulating_contract:
+ dependencies:
+ bulma:
+ specifier: ^1.0.2
+ version: 1.0.2
+ cive:
+ specifier: latest
+ version: 0.4.1(typescript@5.6.2)(zod@3.23.8)
+ react:
+ specifier: ^18.3.1
+ version: 18.3.1
+ react-dom:
+ specifier: ^18.3.1
+ version: 18.3.1(react@18.3.1)
+ devDependencies:
+ '@types/react':
+ specifier: ^18.3.8
+ version: 18.3.9
+ '@types/react-dom':
+ specifier: ^18.3.0
+ version: 18.3.0
+ '@vitejs/plugin-react':
+ specifier: ^4.3.1
+ version: 4.3.1(vite@5.4.4(@types/node@20.14.10))
+ typescript:
+ specifier: ^5.6.2
+ version: 5.6.2
+ vite:
+ specifier: ^5.4.4
+ version: 5.4.4(@types/node@20.14.10)
+
examples/contracts_writing_contract:
dependencies:
bulma: