UNPKG

@moonwell-fi/moonwell-sdk

Version:

TypeScript Interface for Moonwell

319 lines 14 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.trimLeadingEmptySnapshots = trimLeadingEmptySnapshots; exports.getMarketSnapshots = getMarketSnapshots; exports.fetchIsolatedMarketSnapshots = fetchIsolatedMarketSnapshots; const index_js_1 = require("../../../common/index.js"); const lunar_indexer_helpers_js_1 = require("../../../common/lunar-indexer-helpers.js"); const axiosWithRetry_js_1 = require("../../axiosWithRetry.js"); const lunar_indexer_client_js_1 = require("../../lunar-indexer-client.js"); const lunar_indexer_transformers_js_1 = require("../../lunar-indexer-transformers.js"); const lunarIndexerTransform_js_1 = require("../../morpho/markets/lunarIndexerTransform.js"); function trimLeadingEmptySnapshots(snapshots) { let firstActiveTimestamp = Number.POSITIVE_INFINITY; for (const s of snapshots) { if ((s.totalSupply > 0 || s.totalBorrows > 0) && s.timestamp < firstActiveTimestamp) { firstActiveTimestamp = s.timestamp; } } if (firstActiveTimestamp === Number.POSITIVE_INFINITY) return []; return snapshots.filter((s) => s.timestamp >= firstActiveTimestamp); } async function getMarketSnapshots(client, args) { const environment = (0, index_js_1.getEnvironmentFromArgs)(client, args); if (!environment) { return []; } if (args?.type === "core") { const snapshots = await fetchCoreMarketSnapshots(args.marketId, environment, args.period, args.startTime, args.endTime); return trimLeadingEmptySnapshots(snapshots); } const snapshots = await fetchIsolatedMarketSnapshots(args.marketId, environment, args.period, args.startTime, args.endTime); const marketConfig = Object.values(environment.config.morphoMarkets).find((m) => m.id.toLowerCase() === args.marketId.toLowerCase()); const loanSymbol = marketConfig ? environment.config.tokens[marketConfig.loanToken]?.symbol : undefined; const collateralSymbol = marketConfig ? environment.config.tokens[marketConfig.collateralToken]?.symbol : undefined; const isNormalizedMarket = (loanSymbol === "ETH" && collateralSymbol === "USDC") || collateralSymbol === "stkWELL"; const result = isNormalizedMarket ? snapshots : snapshots.map((snapshot) => { if (snapshot.totalSupply === 0 || snapshot.loanTokenPrice === 0) return snapshot; const impliedLoanPrice = snapshot.totalSupplyUsd / snapshot.totalSupply; if (impliedLoanPrice < snapshot.loanTokenPrice * 0.1) { return { ...snapshot, totalSupply: snapshot.totalSupplyUsd / snapshot.loanTokenPrice, totalLiquidity: snapshot.totalLiquidityUsd / snapshot.loanTokenPrice, }; } return snapshot; }); return trimLeadingEmptySnapshots(result); } async function fetchCoreMarketSnapshots(marketAddress, environment, period, startTime, endTime) { if (!environment.lunarIndexerUrl) { if (!environment.indexerUrl) return []; try { return await fetchCoreMarketSnapshotsFromPonder(marketAddress, environment); } catch (error) { console.warn(`[getMarketSnapshots] Ponder failed for chain ${environment.chainId}:`, error); environment.onError?.(error, { source: "market-snapshots-ponder", chainId: environment.chainId, }); return []; } } try { return await fetchCoreMarketSnapshotsFromLunar(marketAddress, environment, period, startTime, endTime); } catch (error) { console.warn(`[getMarketSnapshots] Lunar Indexer failed for chain ${environment.chainId}:`, error); environment.onError?.(error, { source: "market-snapshots", chainId: environment.chainId, }); return []; } } async function fetchCoreMarketSnapshotsFromPonder(marketAddress, environment) { if (!environment.indexerUrl) return []; const dailyData = []; let hasNextPage = true; let endCursor; while (hasNextPage) { const result = await (0, axiosWithRetry_js_1.postWithRetry)(environment.indexerUrl, { query: ` query { marketDailySnapshots ( limit: 1000, orderBy: "timestamp" orderDirection: "desc" where: {marketAddress: "${marketAddress.toLowerCase()}", chainId: ${environment.chainId}} ${endCursor ? `after: "${endCursor}"` : ""} ) { items { totalBorrows totalBorrowsUSD totalSupplies totalSuppliesUSD totalLiquidity totalLiquidityUSD baseSupplyApy baseBorrowApy timestamp } pageInfo { hasNextPage endCursor } } } `, }); dailyData.push(...result.data.data.marketDailySnapshots.items.filter((f) => (0, index_js_1.isStartOfDay)(f.timestamp))); hasNextPage = result.data.data.marketDailySnapshots.pageInfo.hasNextPage; endCursor = result.data.data.marketDailySnapshots.pageInfo.endCursor; } if (dailyData.length === 0) return []; return dailyData.map((point) => { const supplied = Number(point.totalSupplies); const borrow = Number(point.totalBorrows); const borrowUsd = Number(point.totalBorrowsUSD); const suppliedUsd = Number(point.totalSuppliesUSD); const liquidity = Math.max(point.totalLiquidity, 0); const liquidityUsd = Math.max(point.totalLiquidityUSD, 0); const price = suppliedUsd / supplied; return { marketId: marketAddress.toLowerCase(), chainId: environment.chainId, timestamp: point.timestamp * 1000, totalSupply: supplied, totalSupplyUsd: suppliedUsd, totalBorrows: borrow, totalBorrowsUsd: borrowUsd, totalLiquidity: liquidity, totalLiquidityUsd: liquidityUsd, totalReallocatableLiquidity: 0, totalReallocatableLiquidityUsd: 0, baseSupplyApy: point.baseSupplyApy, baseBorrowApy: point.baseBorrowApy, collateralTokenPrice: price, loanTokenPrice: price, }; }); } async function fetchCoreMarketSnapshotsFromLunar(marketAddress, environment, period, customStartTime, customEndTime) { if (!environment.lunarIndexerUrl) { throw new Error("Lunar Indexer URL not configured"); } const client = (0, lunar_indexer_client_js_1.createLunarIndexerClient)({ baseUrl: environment.lunarIndexerUrl, timeout: lunar_indexer_client_js_1.DEFAULT_LUNAR_TIMEOUT_MS, }); const marketId = (0, lunar_indexer_helpers_js_1.buildMarketId)(environment.chainId, marketAddress); const { startTime, endTime, granularity } = (0, index_js_1.calculateTimeRange)(period, customStartTime, customEndTime); const allSnapshots = []; let cursor = null; const MAX_PAGES = 100; let page = 0; do { const response = await client.getMarketSnapshots(marketId, { limit: 1000, ...(cursor && { cursor }), granularity: (0, index_js_1.toApiGranularity)(granularity), startTime, endTime, }); const transformed = (0, lunar_indexer_transformers_js_1.transformMarketSnapshots)(response.results, environment.chainId); allSnapshots.push(...transformed); cursor = response.nextCursor; page++; } while (cursor !== null && page < MAX_PAGES); allSnapshots.sort((a, b) => a.timestamp - b.timestamp); return (0, index_js_1.applyGranularity)(allSnapshots, granularity).map((snapshot) => { const supplied = snapshot.totalSupply; const suppliedUsd = snapshot.totalSupplyUsd; const price = supplied > 0 ? suppliedUsd / supplied : 0; return { ...snapshot, collateralTokenPrice: price, loanTokenPrice: price, }; }); } async function fetchWellPricesByTimestamp(lunarIndexerUrl, chainId, wellMarketConfig, startTime) { const wellIsCollateral = wellMarketConfig.collateralToken === "WELL"; const priceMap = new Map(); let cursor; const MAX_PAGES = 100; let page = 0; do { const response = await (0, lunarIndexerTransform_js_1.fetchMarketSnapshotsFromIndexer)(lunarIndexerUrl, chainId, wellMarketConfig.id, { startTime, granularity: "1d", limit: 1000, ...(cursor && { cursor }), }); for (const snapshot of response.results) { const price = Number.parseFloat(wellIsCollateral ? snapshot.collateralTokenPrice : snapshot.loanTokenPrice); if (price > 0) { priceMap.set(snapshot.timestamp * 1000, price); } } cursor = response.nextCursor ?? undefined; page++; } while (cursor !== undefined && page < MAX_PAGES); return priceMap; } async function fetchIsolatedMarketSnapshots(marketAddress, environment, period, customStartTime, customEndTime) { const lunarIndexerUrl = environment.lunarIndexerUrl; if (!lunarIndexerUrl) { return []; } try { return await fetchIsolatedMarketSnapshotsFromLunar(marketAddress, environment, lunarIndexerUrl, period, customStartTime, customEndTime); } catch (error) { console.warn(`[getMarketSnapshots] Lunar Indexer failed for chain ${environment.chainId}:`, error); environment.onError?.(error, { source: "market-snapshots", chainId: environment.chainId, }); return []; } } async function fetchIsolatedMarketSnapshotsFromLunar(marketAddress, environment, lunarIndexerUrl, period, customStartTime, customEndTime) { const { startTime } = (0, index_js_1.calculateTimeRange)(period, customStartTime, customEndTime); const marketConfig = Object.values(environment.config.morphoMarkets).find((m) => m.id.toLowerCase() === marketAddress.toLowerCase()); const loanSymbol = marketConfig ? environment.config.tokens[marketConfig.loanToken]?.symbol : undefined; const collateralSymbol = marketConfig ? environment.config.tokens[marketConfig.collateralToken]?.symbol : undefined; const normalizeToCollateral = loanSymbol === "ETH" && collateralSymbol === "USDC"; const isStkWellMarket = collateralSymbol === "stkWELL"; const wellMarketConfig = isStkWellMarket ? Object.values(environment.config.morphoMarkets).find((m) => m.collateralToken === "WELL" || m.loanToken === "WELL") : undefined; const wellPricesPromise = wellMarketConfig ? fetchWellPricesByTimestamp(lunarIndexerUrl, environment.chainId, wellMarketConfig, startTime) : Promise.resolve(new Map()); const allSnapshots = []; let cursor; const MAX_PAGES = 100; let page = 0; do { const response = await (0, lunarIndexerTransform_js_1.fetchMarketSnapshotsFromIndexer)(lunarIndexerUrl, environment.chainId, marketAddress, { startTime, granularity: "1d", limit: 1000, ...(cursor && { cursor }), }); allSnapshots.push(...response.results .filter((s) => (0, index_js_1.isStartOfDay)(s.timestamp)) .map((s) => (0, lunarIndexerTransform_js_1.transformIsolatedMarketSnapshotFromIndexer)(s, { normalizeToCollateral, }))); cursor = response.nextCursor ?? undefined; page++; } while (cursor !== undefined && page < MAX_PAGES); const sanitizedSnapshots = normalizeToCollateral ? allSnapshots : allSnapshots.map((snapshot) => { if (snapshot.totalSupply === 0 || snapshot.loanTokenPrice === 0) return snapshot; const impliedLoanPrice = snapshot.totalSupplyUsd / snapshot.totalSupply; if (impliedLoanPrice < snapshot.loanTokenPrice * 0.1) { return { ...snapshot, totalSupply: snapshot.totalSupplyUsd / snapshot.loanTokenPrice, totalLiquidity: snapshot.totalLiquidityUsd / snapshot.loanTokenPrice, }; } return snapshot; }); if (isStkWellMarket) { const wellPriceByTimestampMs = await wellPricesPromise; return sanitizedSnapshots.map((snapshot) => { let collateralTokenPrice = snapshot.collateralTokenPrice; if (collateralTokenPrice === 0) { const wellPrice = wellPriceByTimestampMs.get(snapshot.timestamp); if (wellPrice) collateralTokenPrice = wellPrice; } const totalSupply = collateralTokenPrice > 0 ? snapshot.totalSupplyUsd / collateralTokenPrice : snapshot.totalSupply; const totalLiquidity = collateralTokenPrice > 0 ? snapshot.totalLiquidityUsd / collateralTokenPrice : snapshot.totalLiquidity; const totalReallocatableLiquidity = collateralTokenPrice > 0 ? snapshot.totalReallocatableLiquidityUsd / collateralTokenPrice : snapshot.totalReallocatableLiquidity; return { ...snapshot, collateralTokenPrice, totalSupply, totalLiquidity, totalReallocatableLiquidity, }; }); } return sanitizedSnapshots; } //# sourceMappingURL=getMarketSnapshots.js.map