0xtrails
Version:
SDK for Trails
169 lines (152 loc) • 5.84 kB
text/typescript
import { useAaveMarkets, chainId } from "@aave/react"
import { useMemo } from "react"
import { logger } from "./logger.js"
// Chain ID to Aave market name mapping
const CHAIN_TO_MARKET_NAME: Record<number, string> = {
1: "proto_mainnet_v3", // Ethereum Mainnet
8453: "proto_base_v3", // Base
42161: "proto_arbitrum_v3", // Arbitrum
137: "proto_polygon_v3", // Polygon
10: "proto_optimism_v3", // Optimism
100: "proto_gnosis_v3", // Gnosis
}
// List: https://aave.com/docs/resources/addresses
const WRAPPED_TOKEN_GATEWAY_ADDRESS: Record<number, string> = {
1: "0xd01607c3C5eCABa394D8be377a08590149325722",
137: "0xBC302053db3aA514A3c86B9221082f162B91ad63",
42161: "0x5283BEcEd7ADF6D003225C13896E536f2D4264FF",
10: "0x5f2508cAE9923b02316254026CD43d7902866725",
8453: "0xa0d9C1E9E48Ca30c8d8C3B5D69FF5dc1f6DFfC24",
100: "0x721B9abAb6511b46b9ee83A1aba23BDAcB004149",
}
export function getAaveV3WrappedTokenGatewayAddress(
chainId: number,
): string | null {
return WRAPPED_TOKEN_GATEWAY_ADDRESS[chainId] ?? null
}
// Pool data interface
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 useAavePools() {
const {
data: markets,
loading,
error,
} = useAaveMarkets({
chainIds: [
chainId(1),
chainId(8453),
chainId(42161),
chainId(137),
chainId(10),
], // Ethereum, Base, Arbitrum, Polygon, Optimism
})
// logger.console.log("[trails-sdk] === AAVE HOOK DEBUG ===")
// logger.console.log("[trails-sdk] Aave markets data:", markets)
// logger.console.log("[trails-sdk] Loading:", loading)
// logger.console.log("[trails-sdk] Error:", error)
// logger.console.log("[trails-sdk] Markets type:", typeof markets)
// logger.console.log("[trails-sdk] Markets length:", markets?.length)
// logger.console.log("[trails-sdk] ========================")
// Transform Aave markets data to our Pool interface with caching
const pools: Pool[] = useMemo(() => {
if (!markets) return []
return markets.flatMap((market) => {
logger.console.log("[trails-sdk] Processing market:", market)
logger.console.log("[trails-sdk] Market chain:", market.chain)
logger.console.log("[trails-sdk] Supply reserves:", market.supplyReserves)
logger.console.log(
"[trails-sdk] Supply reserves type:",
typeof market.supplyReserves,
)
logger.console.log(
"[trails-sdk] Supply reserves length:",
market.supplyReserves?.length,
)
if (!market.supplyReserves || market.supplyReserves.length === 0) {
logger.console.log(
"[trails-sdk] No supply reserves found for market:",
market.chain.chainId,
)
return []
}
return (
market.supplyReserves
?.filter((reserve: any) => {
// Check if reserve has supply info and is not frozen/paused
const hasSupplyInfo =
reserve.supplyInfo && !reserve.isFrozen && !reserve.isPaused
const hasLiquidity = parseFloat(reserve.size?.usd || "0") > 0
// logger.console.log(
// `[trails-sdk] Reserve ${reserve.underlyingToken?.symbol}: hasSupplyInfo=${hasSupplyInfo}, hasLiquidity=${hasLiquidity}, sizeUSD=${reserve.size?.usd}`,
// )
return hasSupplyInfo && hasLiquidity
})
.map((reserve: any) => {
const tokenMetadata = {
symbol: reserve.underlyingToken?.symbol || "UNKNOWN",
name: reserve.underlyingToken?.name || "Unknown Token",
decimals: reserve.underlyingToken?.decimals || 18,
}
const pool = {
id: `${reserve.underlyingToken?.address}-${market.chain.chainId}-${reserve.aToken?.address}`,
name: `${tokenMetadata.symbol} Market`,
protocol: "Aave",
chainId: market.chain.chainId,
apy: parseFloat(reserve.supplyInfo?.apy?.value || "0") * 100, // Convert to percentage
tvl: parseFloat(reserve.size?.usd || "0"),
token: {
symbol: tokenMetadata.symbol,
name: tokenMetadata.name,
address: reserve.underlyingToken?.address,
decimals: tokenMetadata.decimals,
logoUrl:
"logoUrl" in tokenMetadata
? tokenMetadata.logoUrl
: reserve.underlyingToken?.imageUrl,
},
depositAddress: market.address,
isActive: !reserve.isFrozen && !reserve.isPaused,
protocolUrl: "https://app.aave.com/",
poolUrl: `https://app.aave.com/reserve-overview/?underlyingAsset=${reserve.underlyingToken?.address?.toLowerCase()}&marketName=${CHAIN_TO_MARKET_NAME[market.chain.chainId] || "proto_mainnet_v3"}`,
wrappedTokenGatewayAddress:
getAaveV3WrappedTokenGatewayAddress(market.chain.chainId) ||
undefined,
}
// logger.console.log("[trails-sdk] pool object:", pool)
return pool
}) || []
)
})
}, [markets])
// logger.console.log("[trails-sdk] Final pools array:", pools)
// logger.console.log("[trails-sdk] Final pools length:", pools.length)
// Sort by APY descending with caching
const sortedPools = useMemo(() => {
return pools.sort((a: Pool, b: Pool) => b.apy - a.apy)
}, [pools])
return {
data: sortedPools,
loading,
error,
}
}
export default useAavePools