11"use client" ;
22
3+ import { parseAsString , useQueryState } from "nuqs" ;
34import {
45 AbiFunction ,
56 AbiItem ,
@@ -11,7 +12,7 @@ import {
1112} from "viem" ;
1213import { formatAbiItem } from "viem/utils" ;
1314import * as z from "zod" ;
14- import { useMemo , useState } from "react" ;
15+ import { useCallback , useEffect , useMemo , useState } from "react" ;
1516import "react18-json-view/src/dark.css" ;
1617import "react18-json-view/src/style.css" ;
1718import { useForm } from "react-hook-form" ;
@@ -90,66 +91,69 @@ function decodeAbiItem(abiItem: AbiFunction | AbiError, data: Hex): DecodedFunct
9091export function DecodeForm ( ) {
9192 const { data : worldData , isLoading : isWorldAbiLoading } = useWorldAbiQuery ( ) ;
9293 const { data : systemData , isLoading : isSystemAbisLoading } = useSystemAbisQuery ( ) ;
94+ const [ encoded , setEncoded ] = useQueryState ( "encoded" , parseAsString . withDefault ( "" ) ) ;
9395 const [ decoded , setDecoded ] = useState < AbiFunction | AbiError | ResourceItem | SelectorDatabase > ( ) ;
94- const [ encoded , setEncoded ] = useState < string | undefined > ( ) ;
9596 const form = useForm < z . infer < typeof formSchema > > ( {
9697 resolver : zodResolver ( formSchema ) ,
9798 } ) ;
9899
99- const onSubmit = async ( { encodedData } : z . infer < typeof formSchema > ) => {
100- setEncoded ( encodedData ) ;
101- if ( ! encodedData ) return ;
100+ const onSubmit = useCallback (
101+ async ( { encodedData } : z . infer < typeof formSchema > ) => {
102+ setEncoded ( encodedData || null ) ;
103+ if ( ! encodedData ) return ;
102104
103- const selector = encodedData . substring ( 0 , 10 ) ;
104- const worldAbi = worldData ?. abi || [ ] ;
105- const systemsAbis = systemData ? Object . values ( systemData ) : [ ] ;
106- const abis = [ worldAbi , ...systemsAbis ] . flat ( ) ;
105+ const selector = encodedData . substring ( 0 , 10 ) ;
106+ const worldAbi = worldData ?. abi || [ ] ;
107+ const systemsAbis = systemData ? Object . values ( systemData ) : [ ] ;
108+ const abis = [ worldAbi , ...systemsAbis ] . flat ( ) ;
107109
108- // Try to find matching ABI item
109- const abiItem = abis . find ( ( item ) : item is AbiFunction | AbiError => {
110- if ( isAbiFunction ( item ) ) {
111- return toFunctionSelector ( item ) === selector ;
112- }
113- if ( isAbiError ( item ) ) {
114- return getErrorSelector ( item ) === selector ;
115- }
116- return false ;
117- } ) ;
118-
119- if ( abiItem ) {
120- setDecoded ( abiItem ) ;
121- return ;
122- }
110+ // Try to find matching ABI item
111+ const abiItem = abis . find ( ( item ) : item is AbiFunction | AbiError => {
112+ if ( isAbiFunction ( item ) ) {
113+ return toFunctionSelector ( item ) === selector ;
114+ }
115+ if ( isAbiError ( item ) ) {
116+ return getErrorSelector ( item ) === selector ;
117+ }
118+ return false ;
119+ } ) ;
123120
124- // Try to decode as resource
125- try {
126- const resource = hexToResource ( encodedData as Hex ) ;
127- if ( resource ) {
128- setDecoded ( { type : "resource" , id : encodedData , resource } ) ;
121+ if ( abiItem ) {
122+ setDecoded ( abiItem ) ;
129123 return ;
130124 }
131- } catch {
132- // Error decoding resource
133- }
134125
135- // Try to find in 4-byte database
136- if ( selector . length !== 10 ) return ;
137- try {
138- const response = await fetch ( `https://www.4byte.directory/api/v1/signatures/?hex_signature=${ selector } ` ) ;
139- const data = await response . json ( ) ;
140- if ( data . results . length > 0 ) {
141- setDecoded ( {
142- type : "signature" ,
143- selectors : data . results . map ( ( result : { text_signature : string } ) => result . text_signature ) ,
144- } ) ;
145- return ;
126+ // Try to decode as resource
127+ try {
128+ const resource = hexToResource ( encodedData as Hex ) ;
129+ if ( resource ) {
130+ setDecoded ( { type : "resource" , id : encodedData , resource } ) ;
131+ return ;
132+ }
133+ } catch {
134+ // Error decoding resource
146135 }
147- } catch {
148- // Error fetching 4byte data
149- }
150136
151- setDecoded ( undefined ) ;
152- } ;
137+ // Try to find in 4-byte database
138+ if ( selector . length !== 10 ) return ;
139+ try {
140+ const response = await fetch ( `https://www.4byte.directory/api/v1/signatures/?hex_signature=${ selector } ` ) ;
141+ const data = await response . json ( ) ;
142+ if ( data . results . length > 0 ) {
143+ setDecoded ( {
144+ type : "signature" ,
145+ selectors : data . results . map ( ( result : { text_signature : string } ) => result . text_signature ) ,
146+ } ) ;
147+ return ;
148+ }
149+ } catch {
150+ // Error fetching 4byte data
151+ }
152+
153+ setDecoded ( undefined ) ;
154+ } ,
155+ [ setEncoded , worldData ?. abi , systemData ] ,
156+ ) ;
153157
154158 const results = useMemo < Result [ ] > ( ( ) => {
155159 if ( ! decoded || ! encoded ) return [ ] ;
@@ -182,27 +186,44 @@ export function DecodeForm() {
182186 return [ ] ;
183187 } , [ decoded , encoded ] ) ;
184188
189+ useEffect ( ( ) => {
190+ if ( encoded ) {
191+ form . setValue ( "encodedData" , encoded ) ;
192+ form . handleSubmit ( onSubmit ) ( ) ;
193+ }
194+ } , [ encoded , form , onSubmit ] ) ;
195+
185196 if ( isWorldAbiLoading || isSystemAbisLoading ) {
186197 return < Skeleton className = "h-[152px] w-full" /> ;
187198 }
188199
189200 return (
190201 < Form { ...form } >
191202 < form onSubmit = { form . handleSubmit ( onSubmit ) } className = "space-y-4" >
192- < FormField
193- control = { form . control }
194- name = "encodedData"
195- render = { ( { field } ) => (
196- < FormItem >
197- < FormLabel > Encoded data</ FormLabel >
198- < FormControl >
199- < Input placeholder = "0xf0f0f0f0" type = "text" { ...field } />
200- </ FormControl >
201- < FormDescription > Decode function, error or resource data</ FormDescription >
202- < FormMessage />
203- </ FormItem >
204- ) }
205- />
203+ < div className = "flex items-center justify-between" >
204+ < FormField
205+ control = { form . control }
206+ name = "encodedData"
207+ render = { ( { field } ) => (
208+ < FormItem className = "flex-1" >
209+ < div className = "flex w-full items-center justify-between" >
210+ < FormLabel > Encoded data</ FormLabel >
211+ < CopyButton
212+ value = { window . location . href }
213+ disabled = { ! form . watch ( "encodedData" ) }
214+ className = "ml-4 h-8 w-8"
215+ />
216+ </ div >
217+
218+ < FormControl >
219+ < Input placeholder = "0xf0f0f0f0" type = "text" { ...field } />
220+ </ FormControl >
221+ < FormDescription > Decode function, error or resource data</ FormDescription >
222+ < FormMessage />
223+ </ FormItem >
224+ ) }
225+ />
226+ </ div >
206227
207228 { form . formState . isSubmitted && (
208229 < >
0 commit comments