0xtrails
Version:
SDK for Trails
159 lines (136 loc) • 4.13 kB
text/typescript
import { useMemo, useEffect } from "react"
import { useAavePools } from "./aave.js"
import { useMorphoVaults } from "./morpho.js"
import { logger } from "./logger.js"
// Cache configuration
const CACHE_DURATION = 5 * 60 * 1000 // 5 minutes in milliseconds
// Global cache for pools data
let poolsCache: {
data: Pool[]
timestamp: number
aaveData: Pool[] | null
morphoData: Pool[] | null
} | null = null
// Pool data interface (shared across all protocols)
export interface Pool {
id: string
name: string
protocol: string
chainId: number
apy: number
tvl: number
token: {
symbol: string
name: string
address: string
decimals: number
logoUrl?: string
}
depositAddress: string
isActive: boolean
poolUrl?: string
protocolUrl?: string
wrappedTokenGatewayAddress?: string
}
export function usePools() {
// Fetch pools from Aave
const {
data: aavePools,
loading: aaveLoading,
error: aaveError,
} = useAavePools()
// Fetch vaults from Morpho
const {
data: morphoPools,
loading: morphoLoading,
error: morphoError,
} = useMorphoVaults()
// Check if cache is valid
const isCacheValid = useMemo(() => {
if (!poolsCache) return false
const now = Date.now()
const isExpired = now - poolsCache.timestamp > CACHE_DURATION
// Check if underlying data has changed
const aaveDataChanged =
JSON.stringify(poolsCache.aaveData) !== JSON.stringify(aavePools)
const morphoDataChanged =
JSON.stringify(poolsCache.morphoData) !== JSON.stringify(morphoPools)
return !isExpired && !aaveDataChanged && !morphoDataChanged
}, [aavePools, morphoPools])
// Combine and transform all pools with caching
const allPools: Pool[] = useMemo(() => {
// Return cached data if valid
if (isCacheValid && poolsCache) {
logger.console.log("[trails-sdk] Using cached pools data")
return poolsCache.data
}
logger.console.log("[trails-sdk] Generating new pools data")
const pools: Pool[] = []
// Add Aave pools
if (aavePools) {
pools.push(...aavePools)
}
// Add Morpho pools
if (morphoPools) {
pools.push(...morphoPools)
}
// Update cache
poolsCache = {
data: pools,
timestamp: Date.now(),
aaveData: aavePools,
morphoData: morphoPools,
}
return pools
}, [aavePools, morphoPools, isCacheValid])
// Determine overall loading and error states
const loading = useMemo(() => {
// Don't show loading if we have valid cached data
if (isCacheValid && poolsCache) {
return false
}
return aaveLoading || morphoLoading
}, [aaveLoading, morphoLoading, isCacheValid])
const error = useMemo(() => {
// Don't show error if we have valid cached data
if (isCacheValid && poolsCache) {
return null
}
return aaveError || morphoError
}, [aaveError, morphoError, isCacheValid])
// Sort by APY descending with caching
const sortedPools = useMemo(() => {
return allPools.sort((a: Pool, b: Pool) => b.apy - a.apy)
}, [allPools])
// Clear cache when there are errors
useEffect(() => {
if (aaveError || morphoError) {
logger.console.log("[trails-sdk] Clearing cache due to errors")
poolsCache = null
}
}, [aaveError, morphoError])
// logger.console.log("[trails-sdk] === COMBINED POOLS DEBUG ===")
// logger.console.log("[trails-sdk] Cache valid:", isCacheValid)
// logger.console.log("[trails-sdk] Aave pools count:", aavePools?.length || 0)
// logger.console.log("[trails-sdk] Morpho pools count:", morphoPools?.length || 0)
// logger.console.log("[trails-sdk] Total pools count:", sortedPools.length)
// logger.console.log(
// "[trails-sdk] Loading states - Aave:",
// aaveLoading,
// "Morpho:",
// morphoLoading,
// )
// logger.console.log(
// "[trails-sdk] Error states - Aave:",
// aaveError,
// "Morpho:",
// morphoError,
// )
// logger.console.log("[trails-sdk] ==============================")
return {
data: sortedPools,
loading,
error,
}
}
export default usePools