UNPKG

@moonwell-fi/moonwell-sdk

Version:

TypeScript Interface for Moonwell

237 lines (211 loc) 6.85 kB
import type { Address } from "viem"; import type { MoonwellClient } from "../../../client/createMoonwellClient.js"; import { Amount } from "../../../common/amount.js"; import { getEnvironmentFromArgs } from "../../../common/index.js"; import type { MorphoMarketParameterType, NetworkParameterType, } from "../../../common/types.js"; import type { Chain } from "../../../environments/index.js"; import { fetchIsolatedMarketSnapshots } from "../../core/markets/getMarketSnapshots.js"; import { fetchMarketSnapshotsFromIndexer } from "./lunarIndexerTransform.js"; export type MarketSnapshot = { timestamp: number; blockNumber: bigint; totalSupplyAssets: Amount; totalBorrowAssets: Amount; totalLiquidity: Amount; totalReallocatableLiquidity: Amount; totalSupplyAssetsUsd: number; totalBorrowAssetsUsd: number; totalLiquidityUsd: number; totalReallocatableLiquidityUsd: number; loanTokenPrice: number; collateralTokenPrice: number; supplyApy: number; borrowApy: number; lltv: number; }; export type GetMarketSnapshotsParameters< environments, network extends Chain | undefined, > = NetworkParameterType<environments, network> & MorphoMarketParameterType<network> & { startTime?: number; endTime?: number; limit?: number; cursor?: string; granularity?: "1h" | "6h" | "1d"; }; export type GetMarketSnapshotsReturnType = Promise<{ snapshots: MarketSnapshot[]; nextCursor?: string; }>; export async function getMarketSnapshots< environments, Network extends Chain | undefined, >( client: MoonwellClient, args: GetMarketSnapshotsParameters<environments, Network>, ): GetMarketSnapshotsReturnType { const environment = getEnvironmentFromArgs(client, args); if (!environment) { throw new Error("Environment not found"); } // Resolve marketId and token config before the URL check so they're available // for both the indexer path and the fallback path. let { marketId, market } = args as unknown as { marketId: Address; market: string; }; if (!marketId) { marketId = environment.config.morphoMarkets[market].id; } const marketConfig = Object.values(environment.config.morphoMarkets).find( (m) => m.id.toLowerCase() === marketId.toLowerCase(), ); if (!marketConfig) { throw new Error(`Market ${marketId} not found in configuration`); } const loanToken = environment.config.tokens[marketConfig.loanToken]; const lunarIndexerUrl = environment.lunarIndexerUrl; if (!lunarIndexerUrl) { // Fallback to Blue API → subgraph via the core fetchIsolatedMarketSnapshots. // blockNumber is not available from these paths; set to 0n as a sentinel value. const coreSnapshots = await fetchIsolatedMarketSnapshots( marketId, environment, undefined, args.startTime, args.endTime, ); const snapshots: MarketSnapshot[] = coreSnapshots.map((s) => ({ timestamp: s.timestamp, blockNumber: 0n, totalSupplyAssets: new Amount( BigInt(Math.round(s.totalSupply * 10 ** loanToken.decimals)), loanToken.decimals, ), totalBorrowAssets: new Amount( BigInt(Math.round(s.totalBorrows * 10 ** loanToken.decimals)), loanToken.decimals, ), totalLiquidity: new Amount( BigInt(Math.round(s.totalLiquidity * 10 ** loanToken.decimals)), loanToken.decimals, ), totalReallocatableLiquidity: new Amount( BigInt( Math.round(s.totalReallocatableLiquidity * 10 ** loanToken.decimals), ), loanToken.decimals, ), totalSupplyAssetsUsd: s.totalSupplyUsd, totalBorrowAssetsUsd: s.totalBorrowsUsd, totalLiquidityUsd: s.totalLiquidityUsd, totalReallocatableLiquidityUsd: s.totalReallocatableLiquidityUsd, loanTokenPrice: s.loanTokenPrice, collateralTokenPrice: s.collateralTokenPrice, supplyApy: s.baseSupplyApy, borrowApy: s.baseBorrowApy, lltv: 0, })); return { snapshots }; } // Build options object with only defined values const options: { startTime?: number; endTime?: number; limit?: number; cursor?: string; granularity?: "1h" | "6h" | "1d"; } = {}; if (args.startTime !== undefined) { options.startTime = args.startTime; } if (args.endTime !== undefined) { options.endTime = args.endTime; } if (args.limit !== undefined) { options.limit = args.limit; } if (args.cursor !== undefined) { options.cursor = args.cursor; } if (args.granularity !== undefined) { options.granularity = args.granularity; } const response = await fetchMarketSnapshotsFromIndexer( lunarIndexerUrl, environment.chainId, marketId, options, ); // Transform snapshots const snapshots: MarketSnapshot[] = response.results.map((snapshot) => { const totalSupplyAssets = new Amount( BigInt( Math.floor( Number.parseFloat(snapshot.totalSupplyAssets) * 10 ** loanToken.decimals, ), ), loanToken.decimals, ); const totalBorrowAssets = new Amount( BigInt( Math.floor( Number.parseFloat(snapshot.totalBorrowAssets) * 10 ** loanToken.decimals, ), ), loanToken.decimals, ); const totalLiquidity = new Amount( BigInt( Math.floor( Number.parseFloat(snapshot.totalLiquidity) * 10 ** loanToken.decimals, ), ), loanToken.decimals, ); const totalReallocatableLiquidity = new Amount( BigInt( Math.floor( Number.parseFloat(snapshot.totalReallocatableLiquidity ?? "0") * 10 ** loanToken.decimals, ), ), loanToken.decimals, ); return { timestamp: snapshot.timestamp, blockNumber: BigInt(snapshot.blockNumber), totalSupplyAssets, totalBorrowAssets, totalLiquidity, totalReallocatableLiquidity, totalSupplyAssetsUsd: Number.parseFloat(snapshot.totalSupplyAssetsUsd), totalBorrowAssetsUsd: Number.parseFloat(snapshot.totalBorrowAssetsUsd), totalLiquidityUsd: Number.parseFloat(snapshot.totalLiquidityUsd), totalReallocatableLiquidityUsd: Number.parseFloat( snapshot.totalReallocatableLiquidityUsd ?? "0", ), loanTokenPrice: Number.parseFloat(snapshot.loanTokenPrice), collateralTokenPrice: Number.parseFloat(snapshot.collateralTokenPrice), supplyApy: Number.parseFloat(snapshot.supplyApy), borrowApy: Number.parseFloat(snapshot.borrowApy), lltv: Number.parseFloat(snapshot.lltv), }; }); const result: { snapshots: MarketSnapshot[]; nextCursor?: string; } = { snapshots, }; if (response.nextCursor !== undefined) { result.nextCursor = response.nextCursor; } return result; }