UNPKG

lending-apy-fetcher-ts

Version:

TypeScript library for fetching APYs from DeFi lending protocols

122 lines (102 loc) 3.17 kB
import { Protocol, ApyData, ApyResult, GroupedApys, BestApyResult, ApyFetcherError } from './types'; export class ApyFetcher { private protocols: Protocol[] = []; constructor(protocols?: Protocol[]) { this.initializeProtocols(protocols || []); } private initializeProtocols(protocols: Protocol[]): void { this.protocols.push(...protocols); } /** * Fetch APYs from all configured protocols * @param gracefulDegradation - Continue with other protocols if one fails */ async fetchApys(gracefulDegradation: boolean = true): Promise<ApyData[]> { const results = await this.fetchApysWithResults(gracefulDegradation); // Aggregate all successful results const allApys: ApyData[] = []; for (const result of results) { if (result.success && result.data) { allApys.push(...result.data); } } return allApys; } /** * Fetch APYs with detailed results per protocol */ async fetchApysWithResults(gracefulDegradation: boolean = true): Promise<ApyResult[]> { const promises = this.protocols.map(async (protocol): Promise<ApyResult> => { try { const data = await protocol.fetchApys(); return { success: true, data, protocol: protocol.name, }; } catch (error) { const apyError = error instanceof ApyFetcherError ? error : new ApyFetcherError(`Failed to fetch from ${protocol.name}`, protocol.name, error as Error); if (!gracefulDegradation) { throw apyError; } return { success: false, error: apyError, protocol: protocol.name, }; } }); return Promise.all(promises); } /** * Get APYs grouped by token symbol */ async getApysByToken(gracefulDegradation: boolean = true): Promise<GroupedApys> { const apys = await this.fetchApys(gracefulDegradation); const grouped: GroupedApys = {}; for (const apy of apys) { if (!grouped[apy.token_symbol]) { grouped[apy.token_symbol] = []; } grouped[apy.token_symbol].push(apy); } // Sort each group by APY descending for (const symbol in grouped) { grouped[symbol].sort((a, b) => b.apy - a.apy); } return grouped; } /** * Get the best APY for a specific token across all protocols */ async getBestApyForToken(tokenSymbol: string, gracefulDegradation: boolean = true): Promise<BestApyResult | null> { const apys = await this.fetchApys(gracefulDegradation); const tokenApys = apys.filter(apy => apy.token_symbol.toLowerCase() === tokenSymbol.toLowerCase() ); if (tokenApys.length === 0) { return null; } // Sort by APY descending tokenApys.sort((a, b) => b.apy - a.apy); return { token_symbol: tokenSymbol, apy: tokenApys[0].apy, network: tokenApys[0].network, }; } /** * Get all available protocols */ getProtocols(): Protocol[] { return [...this.protocols]; } /** * Add a custom protocol */ addProtocol(protocol: Protocol): void { this.protocols.push(protocol); } }