@@ -5,7 +5,9 @@ import { useReadContract, useChainId, useConfig } from 'wagmi'
55import { readContract } from '@wagmi/core'
66import { OracleFactoryAbi } from '@/utils/abi/OracleFactory'
77import { OracleAbi } from '@/utils/abi/Oracle'
8- import { OracleFactories } from '@/utils/addresses'
8+ import { ComposedOracleFactoryAbi } from '@/utils/abi/ComposedOracleFactory'
9+ import { ComposedOracleAbi } from '@/utils/abi/ComposedOracle'
10+ import { OracleFactories , ComposedOracleFactories } from '@/utils/addresses'
911
1012const formatTimestamp = ( value : bigint | undefined | null ) => {
1113 if ( ! value || value === BigInt ( 0 ) ) {
@@ -34,6 +36,12 @@ export interface Oracle {
3436 lastUpdate : string
3537 lastUpdated : string
3638 lastTimestamp : string
39+ isComposed ?: boolean
40+ feedA ?: string
41+ feedB ?: string
42+ operation ?: number
43+ invertResult ?: boolean
44+ defaultSampleSize ?: bigint
3745}
3846
3947export function useOracles ( ) {
@@ -50,30 +58,40 @@ export function useOracles() {
5058 setError ( null )
5159
5260 const factoryAddress = OracleFactories [ chainId as keyof typeof OracleFactories ]
61+ const composedFactoryAddress = ComposedOracleFactories [ chainId as keyof typeof ComposedOracleFactories ]
5362
54- if ( ! factoryAddress || factoryAddress === '0x0000000000000000000000000000000000000000' ) {
55- setError ( 'Oracle Factory not deployed on this network' )
56- setLoading ( false )
57- return
63+ let oracleInfos : Array < { oracle : string ; token : string ; creator : string } > = [ ]
64+ let composedOracleInfos : Array < { oracle : string ; feedA : string ; feedB : string ; operation : number ; creator : string } > = [ ]
65+
66+ // Read standard oracles
67+ if ( factoryAddress && factoryAddress !== '0x0000000000000000000000000000000000000000' ) {
68+ try {
69+ oracleInfos = await readContract ( config , {
70+ address : factoryAddress ,
71+ abi : OracleFactoryAbi ,
72+ functionName : 'allOracles' ,
73+ } ) as any
74+ } catch ( e ) {
75+ console . error ( 'Error fetching standard oracles:' , e )
76+ }
5877 }
5978
60- // Read all oracles from the factory
61- const oracleInfos = await readContract ( config , {
62- address : factoryAddress ,
63- abi : OracleFactoryAbi ,
64- functionName : 'allOracles' ,
65- } ) as Array < { oracle : string ; token : string ; creator : string } >
66-
67- if ( ! oracleInfos || ! Array . isArray ( oracleInfos ) ) {
68- setOracles ( [ ] )
69- setLoading ( false )
70- return
79+ // Read composed oracles
80+ if ( composedFactoryAddress && composedFactoryAddress !== '0x0000000000000000000000000000000000000000' ) {
81+ try {
82+ composedOracleInfos = await readContract ( config , {
83+ address : composedFactoryAddress ,
84+ abi : ComposedOracleFactoryAbi ,
85+ functionName : 'allComposedOracles' ,
86+ } ) as any
87+ } catch ( e ) {
88+ console . error ( 'Error fetching composed oracles:' , e )
89+ }
7190 }
7291
73- // Fetch details for each oracle
74- const oraclePromises = oracleInfos . map ( async ( info : any , index : number ) => {
92+ // Fetch details for standard oracles
93+ const oraclePromises = ( oracleInfos || [ ] ) . map ( async ( info : any , index : number ) => {
7594 try {
76- // Read oracle name and description from the contract
7795 const [ name , description , lastUpdated , lastTimestamp ] = await Promise . all ( [
7896 readContract ( config , {
7997 address : info . oracle as `0x${string } `,
@@ -111,6 +129,7 @@ export function useOracles() {
111129 lastUpdate : new Date ( ) . toISOString ( ) ,
112130 lastUpdated : formatTimestamp ( lastUpdated as bigint ) ,
113131 lastTimestamp : formatTimestamp ( lastTimestamp as bigint ) ,
132+ isComposed : false ,
114133 }
115134 } catch ( err ) {
116135 console . error ( `Error fetching details for oracle ${ info . oracle } :` , err )
@@ -128,12 +147,83 @@ export function useOracles() {
128147 lastUpdate : new Date ( ) . toISOString ( ) ,
129148 lastUpdated : '—' ,
130149 lastTimestamp : '—' ,
150+ isComposed : false ,
131151 }
132152 }
133153 } )
134154
135- const oracleDetails = await Promise . all ( oraclePromises )
136- setOracles ( oracleDetails )
155+ // Fetch details for composed oracles
156+ const composedPromises = ( composedOracleInfos || [ ] ) . map ( async ( info : any , index : number ) => {
157+ try {
158+ const lastUpdated = await readContract ( config , {
159+ address : info . oracle as `0x${string } `,
160+ abi : ComposedOracleAbi ,
161+ functionName : 'lastUpdated' ,
162+ } ) . catch ( ( ) => BigInt ( 0 ) )
163+
164+ return {
165+ id : info . oracle ,
166+ name : `Composed Oracle ${ index + 1 } ` ,
167+ description : `Price Feed` ,
168+ address : info . oracle ,
169+ token : '0x0000000000000000000000000000000000000000' ,
170+ creator : info . creator ,
171+ category : 'Price Feed' ,
172+ status : 'active' as const ,
173+ updateFrequency : '1min' ,
174+ accuracy : '99.9%' ,
175+ lastUpdate : new Date ( ) . toISOString ( ) ,
176+ lastUpdated : formatTimestamp ( lastUpdated as bigint ) ,
177+ lastTimestamp : formatTimestamp ( lastUpdated as bigint ) ,
178+ isComposed : true ,
179+ feedA : info . feedA ,
180+ feedB : info . feedB ,
181+ operation : info . operation ,
182+ }
183+ } catch ( err ) {
184+ console . error ( `Error fetching details for composed oracle ${ info . oracle } :` , err )
185+ return {
186+ id : info . oracle ,
187+ name : `Composed Oracle ${ index + 1 } ` ,
188+ description : 'Error loading price feed' ,
189+ address : info . oracle ,
190+ token : '0x0000000000000000000000000000000000000000' ,
191+ creator : info . creator ,
192+ category : 'Price Feed' ,
193+ status : 'inactive' as const ,
194+ updateFrequency : 'Unknown' ,
195+ accuracy : 'Unknown' ,
196+ lastUpdate : new Date ( ) . toISOString ( ) ,
197+ lastUpdated : '—' ,
198+ lastTimestamp : '—' ,
199+ isComposed : true ,
200+ feedA : info . feedA ,
201+ feedB : info . feedB ,
202+ operation : info . operation ,
203+ }
204+ }
205+ } )
206+
207+ const baseOraclesList = await Promise . all ( oraclePromises )
208+ const composedOraclesList = await Promise . all ( composedPromises )
209+
210+ // Map base addresses to names for dynamic composed labeling
211+ const addressToName = new Map < string , string > ( )
212+ baseOraclesList . forEach ( o => addressToName . set ( o . address . toLowerCase ( ) , o . name ) )
213+
214+ const enhancedComposedOracles = composedOraclesList . map ( co => {
215+ const nameA = addressToName . get ( co . feedA . toLowerCase ( ) ) || co . feedA . slice ( 0 , 6 ) + '...' + co . feedA . slice ( - 4 )
216+ const nameB = addressToName . get ( co . feedB . toLowerCase ( ) ) || co . feedB . slice ( 0 , 6 ) + '...' + co . feedB . slice ( - 4 )
217+ const opSymbol = co . operation === 0 ? '×' : '/'
218+ const combinedName = `${ nameA } ${ opSymbol } ${ nameB } `
219+ return {
220+ ...co ,
221+ name : combinedName ,
222+ description : `${ combinedName } Price Feed` ,
223+ }
224+ } )
225+
226+ setOracles ( [ ...baseOraclesList , ...enhancedComposedOracles ] )
137227 } catch ( err ) {
138228 console . error ( 'Error fetching oracles:' , err )
139229 setError ( 'Failed to fetch oracles from contract' )
@@ -184,45 +274,163 @@ export function useOracle(oracleAddress: string, targetChainId?: number) {
184274 }
185275
186276 try {
187- // Read oracle details from the contract
188- const [ name , description , lastUpdated , lastTimestamp ] = await Promise . all ( [
189- readContract ( config , {
190- address : oracleAddress as `0x${string } `,
191- abi : OracleAbi ,
192- functionName : 'name' ,
193- } ) . catch ( ( ) => 'Unknown Oracle' ) ,
194- readContract ( config , {
195- address : oracleAddress as `0x${string } `,
196- abi : OracleAbi ,
197- functionName : 'description' ,
198- } ) . catch ( ( ) => 'No description available' ) ,
199- readContract ( config , {
200- address : oracleAddress as `0x${string } `,
201- abi : OracleAbi ,
202- functionName : 'lastUpdated' ,
203- } ) . catch ( ( ) => BigInt ( 0 ) ) ,
204- readContract ( config , {
277+ // Check if it is a composed oracle first by reading feedA
278+ let isComposed = false
279+ let feedA = '0x0000000000000000000000000000000000000000'
280+ let feedB = '0x0000000000000000000000000000000000000000'
281+ let invertResult = false
282+ let defaultSampleSize = BigInt ( 100 )
283+
284+ try {
285+ const fA = await readContract ( config , {
205286 address : oracleAddress as `0x${string } `,
206- abi : OracleAbi ,
207- functionName : 'lastTimestamp' ,
208- } ) . catch ( ( ) => BigInt ( 0 ) ) ,
209- ] )
287+ abi : ComposedOracleAbi ,
288+ functionName : 'feedA' ,
289+ } )
290+ feedA = fA as string
291+ isComposed = true
292+ } catch ( e ) {
293+ // Standard base oracle
294+ }
210295
211- setOracle ( {
212- id : oracleAddress ,
213- name : name as string ,
214- description : description as string ,
215- address : oracleAddress ,
216- token : '0x0000000000000000000000000000000000000000' ,
217- creator : '0x0000000000000000000000000000000000000000' ,
218- category : 'Price Feed' ,
219- status : 'active' ,
220- updateFrequency : '1min' ,
221- accuracy : '99.9%' ,
222- lastUpdate : new Date ( ) . toISOString ( ) ,
223- lastUpdated : formatTimestamp ( lastUpdated as bigint ) ,
224- lastTimestamp : formatTimestamp ( lastTimestamp as bigint ) ,
225- } )
296+ if ( isComposed ) {
297+ try {
298+ const [ fB , inv , size ] = await Promise . all ( [
299+ readContract ( config , {
300+ address : oracleAddress as `0x${string } `,
301+ abi : ComposedOracleAbi ,
302+ functionName : 'feedB' ,
303+ } ) ,
304+ readContract ( config , {
305+ address : oracleAddress as `0x${string } `,
306+ abi : ComposedOracleAbi ,
307+ functionName : 'invertResult' ,
308+ } ) ,
309+ readContract ( config , {
310+ address : oracleAddress as `0x${string } `,
311+ abi : ComposedOracleAbi ,
312+ functionName : 'defaultSampleSize' ,
313+ } ) ,
314+ ] )
315+ feedB = fB as string
316+ invertResult = inv as boolean
317+ defaultSampleSize = size as bigint
318+ } catch ( e ) {
319+ console . error ( 'Error fetching remaining composed oracle parameters:' , e )
320+ }
321+ }
322+
323+ if ( isComposed ) {
324+ // Query dynamic names for parent feeds
325+ const [ nameA , nameB , lastUpdated ] = await Promise . all ( [
326+ readContract ( config , {
327+ address : feedA as `0x${string } `,
328+ abi : OracleAbi ,
329+ functionName : 'name' ,
330+ } ) . catch ( ( ) => feedA . slice ( 0 , 6 ) + '...' + feedA . slice ( - 4 ) ) ,
331+ readContract ( config , {
332+ address : feedB as `0x${string } `,
333+ abi : OracleAbi ,
334+ functionName : 'name' ,
335+ } ) . catch ( ( ) => feedB . slice ( 0 , 6 ) + '...' + feedB . slice ( - 4 ) ) ,
336+ readContract ( config , {
337+ address : oracleAddress as `0x${string } `,
338+ abi : ComposedOracleAbi ,
339+ functionName : 'lastUpdated' ,
340+ } ) . catch ( ( ) => BigInt ( 0 ) ) ,
341+ ] )
342+
343+ // Retrieve operation and creator from ComposedOracleFactory
344+ const composedFactoryAddress = ComposedOracleFactories [ chainId as keyof typeof ComposedOracleFactories ]
345+ let operation = 0
346+ let creator = '0x0000000000000000000000000000000000000000'
347+
348+ if ( composedFactoryAddress ) {
349+ try {
350+ const composedOracleInfos = await readContract ( config , {
351+ address : composedFactoryAddress ,
352+ abi : ComposedOracleFactoryAbi ,
353+ functionName : 'allComposedOracles' ,
354+ } ) as any [ ]
355+
356+ const matchingInfo = composedOracleInfos . find (
357+ ( info : any ) => info . oracle . toLowerCase ( ) === oracleAddress . toLowerCase ( )
358+ )
359+ if ( matchingInfo ) {
360+ operation = matchingInfo . operation
361+ creator = matchingInfo . creator
362+ }
363+ } catch ( e ) {
364+ console . error ( 'Error matching composed oracle details from factory:' , e )
365+ }
366+ }
367+
368+ const opSymbol = operation === 0 ? '×' : '/'
369+
370+ const combinedName = `${ nameA } ${ opSymbol } ${ nameB } `
371+ setOracle ( {
372+ id : oracleAddress ,
373+ name : combinedName ,
374+ description : `${ combinedName } Price Feed` ,
375+ address : oracleAddress ,
376+ token : '0x0000000000000000000000000000000000000000' ,
377+ creator : creator ,
378+ category : 'Price Feed' ,
379+ status : 'active' ,
380+ updateFrequency : '1min' ,
381+ accuracy : '99.9%' ,
382+ lastUpdate : new Date ( ) . toISOString ( ) ,
383+ lastUpdated : formatTimestamp ( lastUpdated as bigint ) ,
384+ lastTimestamp : formatTimestamp ( lastUpdated as bigint ) ,
385+ isComposed : true ,
386+ feedA,
387+ feedB,
388+ operation,
389+ invertResult,
390+ defaultSampleSize,
391+ } )
392+ } else {
393+ // Standard base oracle
394+ const [ name , description , lastUpdated , lastTimestamp ] = await Promise . all ( [
395+ readContract ( config , {
396+ address : oracleAddress as `0x${string } `,
397+ abi : OracleAbi ,
398+ functionName : 'name' ,
399+ } ) . catch ( ( ) => 'Unknown Oracle' ) ,
400+ readContract ( config , {
401+ address : oracleAddress as `0x${string } `,
402+ abi : OracleAbi ,
403+ functionName : 'description' ,
404+ } ) . catch ( ( ) => 'No description available' ) ,
405+ readContract ( config , {
406+ address : oracleAddress as `0x${string } `,
407+ abi : OracleAbi ,
408+ functionName : 'lastUpdated' ,
409+ } ) . catch ( ( ) => BigInt ( 0 ) ) ,
410+ readContract ( config , {
411+ address : oracleAddress as `0x${string } `,
412+ abi : OracleAbi ,
413+ functionName : 'lastTimestamp' ,
414+ } ) . catch ( ( ) => BigInt ( 0 ) ) ,
415+ ] )
416+
417+ setOracle ( {
418+ id : oracleAddress ,
419+ name : name as string ,
420+ description : description as string ,
421+ address : oracleAddress ,
422+ token : '0x0000000000000000000000000000000000000000' ,
423+ creator : '0x0000000000000000000000000000000000000000' ,
424+ category : 'Price Feed' ,
425+ status : 'active' ,
426+ updateFrequency : '1min' ,
427+ accuracy : '99.9%' ,
428+ lastUpdate : new Date ( ) . toISOString ( ) ,
429+ lastUpdated : formatTimestamp ( lastUpdated as bigint ) ,
430+ lastTimestamp : formatTimestamp ( lastTimestamp as bigint ) ,
431+ isComposed : false ,
432+ } )
433+ }
226434 } catch ( err ) {
227435 console . error ( 'Error fetching oracle details:' , err )
228436 setError ( 'Failed to fetch oracle details' )
0 commit comments