11import { useParams } from "next/navigation" ;
2- import { BaseError , Hex , TransactionReceipt , decodeFunctionData , parseEventLogs } from "viem" ;
2+ import {
3+ Address ,
4+ BaseError ,
5+ Hash ,
6+ Transaction ,
7+ TransactionReceipt ,
8+ decodeFunctionData ,
9+ getAddress ,
10+ parseAbi ,
11+ parseEventLogs ,
12+ } from "viem" ;
13+ import { UserOperation , entryPoint07Abi , entryPoint07Address } from "viem/account-abstraction" ;
314import { useConfig , useWatchBlocks } from "wagmi" ;
415import { getTransaction , simulateContract , waitForTransactionReceipt } from "wagmi/actions" ;
516import { useStore } from "zustand" ;
@@ -8,22 +19,106 @@ import { store as observerStore } from "../../../../../../observer/store";
819import { useChain } from "../../../../hooks/useChain" ;
920import { useWorldAbiQuery } from "../../../../queries/useWorldAbiQuery" ;
1021import { store as worldStore } from "../store" ;
22+ import { userOperationEventAbi } from "./abis/userOperationEventAbi" ;
23+ import { getDecodedUserOperationCalls } from "./utils/getDecodedUserOperationCalls" ;
1124
1225export function TransactionsWatcher ( ) {
1326 const { id : chainId } = useChain ( ) ;
14- const { worldAddress } = useParams < { worldAddress : string } > ( ) ;
27+ const { worldAddress } = useParams < { worldAddress : Address } > ( ) ;
1528 const wagmiConfig = useConfig ( ) ;
1629 const { data : worldAbiData } = useWorldAbiQuery ( ) ;
1730 const abi = worldAbiData ?. abi ;
1831 const { transactions, setTransaction, updateTransaction } = useStore ( worldStore ) ;
1932 const observerWrites = useStore ( observerStore , ( state ) => state . writes ) ;
2033
21- const handleTransaction = useCallback (
22- async ( hash : Hex , timestamp : bigint ) => {
34+ const handleUserOperation = useCallback (
35+ ( {
36+ hash,
37+ writeId,
38+ timestamp,
39+ receipt,
40+ transaction,
41+ userOperation,
42+ } : {
43+ hash : Hash ;
44+ writeId ?: string ;
45+ timestamp : bigint ;
46+ receipt : TransactionReceipt ;
47+ transaction : Transaction ;
48+ userOperation : UserOperation < "0.7" > ;
49+ } ) => {
2350 if ( ! abi ) return ;
2451
25- const transaction = await getTransaction ( wagmiConfig , { hash } ) ;
26- if ( transaction . to !== worldAddress ) return ;
52+ const decodedSmartAccountCall = decodeFunctionData ( {
53+ abi : parseAbi ( [
54+ "function execute(address target, uint256 value, bytes calldata data)" ,
55+ "function executeBatch((address target,uint256 value,bytes data)[])" ,
56+ ] ) ,
57+ data : userOperation . callData ,
58+ } ) ;
59+
60+ const { functionName : decodedFunctionName , args : decodedArgs } = decodedSmartAccountCall ;
61+ const calls = getDecodedUserOperationCalls ( {
62+ abi,
63+ functionName : decodedFunctionName ,
64+ decodedArgs,
65+ } ) . filter ( ( { to } ) => to && getAddress ( to ) === getAddress ( worldAddress ) ) ;
66+ if ( calls . length === 0 ) return ;
67+
68+ const logs = parseEventLogs ( {
69+ abi : [ ...abi , userOperationEventAbi ] ,
70+ logs : receipt . logs ,
71+ } ) ;
72+ const userOperationEvent = logs . find ( ( { eventName } ) => eventName === "UserOperationEvent" ) ;
73+
74+ setTransaction ( {
75+ hash,
76+ writeId : writeId ?? hash ,
77+ from : transaction . from ,
78+ timestamp,
79+ transaction,
80+ calls,
81+ receipt,
82+ logs,
83+ value : transaction . value ,
84+ status : userOperationEvent ?. args . success ? "success" : "reverted" ,
85+ } ) ;
86+ } ,
87+ [ abi , setTransaction , worldAddress ] ,
88+ ) ;
89+
90+ const handleUserOperations = useCallback (
91+ async ( { writeId, timestamp, transaction } : { writeId ?: string ; timestamp : bigint ; transaction : Transaction } ) => {
92+ if ( ! abi ) return ;
93+
94+ const hash = transaction . hash ;
95+ const receipt = await waitForTransactionReceipt ( wagmiConfig , { hash : transaction . hash } ) ;
96+ const decodedEntryPointCall = decodeFunctionData ( {
97+ abi : entryPoint07Abi ,
98+ data : transaction . input ,
99+ } ) ;
100+
101+ const userOperations = decodedEntryPointCall . args [ 0 ] as never as UserOperation < "0.7" > [ ] ;
102+ for ( const userOperation of userOperations ) {
103+ handleUserOperation ( { hash, writeId, timestamp, receipt, transaction, userOperation } ) ;
104+ }
105+ } ,
106+ [ abi , handleUserOperation , wagmiConfig ] ,
107+ ) ;
108+
109+ const handleAuthenticTransaction = useCallback (
110+ async ( {
111+ writeId,
112+ hash,
113+ timestamp,
114+ transaction,
115+ } : {
116+ hash : Hash ;
117+ writeId ?: string ;
118+ timestamp : bigint ;
119+ transaction : Transaction ;
120+ } ) => {
121+ if ( ! abi || ! transaction . to ) return ;
27122
28123 let functionName : string | undefined ;
29124 let args : readonly unknown [ ] | undefined ;
@@ -38,18 +133,20 @@ export function TransactionsWatcher() {
38133 functionName = transaction . input . length > 10 ? transaction . input . slice ( 0 , 10 ) : "unknown" ;
39134 }
40135
41- const write = Object . values ( observerWrites ) . find ( ( write ) => write . hash === hash ) ;
42136 setTransaction ( {
43137 hash,
44- writeId : write ?. writeId ?? hash ,
138+ writeId : writeId ?? hash ,
45139 from : transaction . from ,
46140 timestamp,
47141 transaction,
48142 status : "pending" ,
49- functionData : {
50- functionName,
51- args,
52- } ,
143+ calls : [
144+ {
145+ to : transaction . to ,
146+ functionName,
147+ args,
148+ } ,
149+ ] ,
53150 value : transaction . value ,
54151 } ) ;
55152
@@ -92,16 +189,29 @@ export function TransactionsWatcher() {
92189 error : transactionError as BaseError ,
93190 } ) ;
94191 } ,
95- [ abi , wagmiConfig , worldAddress , observerWrites , setTransaction , updateTransaction ] ,
192+ [ abi , wagmiConfig , worldAddress , setTransaction , updateTransaction ] ,
193+ ) ;
194+
195+ const handleTransaction = useCallback (
196+ async ( { hash, writeId, timestamp } : { hash : Hash ; timestamp : bigint ; writeId ?: string } ) => {
197+ if ( ! abi ) return ;
198+
199+ const transaction = await getTransaction ( wagmiConfig , { hash } ) ;
200+ if ( transaction . to && getAddress ( transaction . to ) === getAddress ( entryPoint07Address ) ) {
201+ handleUserOperations ( { writeId, timestamp, transaction } ) ;
202+ } else if ( transaction . to && getAddress ( transaction . to ) === getAddress ( worldAddress ) ) {
203+ handleAuthenticTransaction ( { hash, writeId, timestamp, transaction } ) ;
204+ }
205+ } ,
206+ [ abi , wagmiConfig , worldAddress , handleUserOperations , handleAuthenticTransaction ] ,
96207 ) ;
97208
98209 useEffect ( ( ) => {
99- for ( const write of Object . values ( observerWrites ) ) {
100- const hash = write . hash ;
101- if ( hash && write . address . toLowerCase ( ) === worldAddress . toLowerCase ( ) ) {
210+ for ( const { hash, writeId, time } of Object . values ( observerWrites ) ) {
211+ if ( hash ) {
102212 const transaction = transactions . find ( ( transaction ) => transaction . hash === hash ) ;
103213 if ( ! transaction ) {
104- handleTransaction ( hash , BigInt ( write . time ) / 1000n ) ;
214+ handleTransaction ( { hash, writeId , timestamp : BigInt ( time ) / 1000n } ) ;
105215 }
106216 }
107217 }
@@ -111,7 +221,7 @@ export function TransactionsWatcher() {
111221 onBlock ( block ) {
112222 for ( const hash of block . transactions ) {
113223 if ( transactions . find ( ( transaction ) => transaction . hash === hash ) ) continue ;
114- handleTransaction ( hash , block . timestamp ) ;
224+ handleTransaction ( { hash, timestamp : block . timestamp } ) ;
115225 }
116226 } ,
117227 chainId,
0 commit comments