UNPKG

@moonwell-fi/moonwell-sdk

Version:

TypeScript Interface for Moonwell

162 lines (141 loc) 4.58 kB
import type { MoonwellClient } from "../../../client/createMoonwellClient.js"; import { applyGranularity, calculateTimeRange, getEnvironmentFromArgs, toApiGranularity, } from "../../../common/index.js"; import type { MorphoVaultParameterType, NetworkParameterType, } from "../../../common/types.js"; import type { Chain } from "../../../environments/index.js"; import type { MorphoVaultSnapshot } from "../../../types/morphoVault.js"; import { fetchVaultSnapshotsFromIndexer, getV1VaultKey, transformVaultSnapshotsFromIndexer, } from "./lunarIndexerTransform.js"; export type GetMorphoVaultSnapshotsParameters< environments, network extends Chain | undefined, > = NetworkParameterType<environments, network> & MorphoVaultParameterType<network> & { period?: "1M" | "3M" | "1Y" | "ALL"; startTime?: number; endTime?: number; }; export type GetMorphoVaultSnapshotsReturnType = Promise<MorphoVaultSnapshot[]>; export async function getMorphoVaultSnapshots< environments, Network extends Chain | undefined, >( client: MoonwellClient, args: GetMorphoVaultSnapshotsParameters<environments, Network>, ): GetMorphoVaultSnapshotsReturnType { const environment = getEnvironmentFromArgs(client, args); if (!environment) { return []; } const { vaultAddress: requestedVaultAddress, period, startTime: customStartTime, endTime: customEndTime, } = args as GetMorphoVaultSnapshotsParameters<environments, undefined>; // For V2 vaults, fetch snapshots using the paired V1 address. // Historical snapshots are indexed against V1 since that is where assets are held. // The original (V2) address is preserved so that returned snapshots carry the // address the caller requested, not the internal V1 address used for fetching. let fetchAddress = requestedVaultAddress; const matchedEntry = Object.entries(environment.config.vaults).find( ([, vaultConfig]) => environment.config.tokens[ vaultConfig.vaultToken as string ]?.address?.toLowerCase() === requestedVaultAddress.toLowerCase(), ); if (matchedEntry !== undefined) { const [matchedVaultKey] = matchedEntry; const v1VaultKey = getV1VaultKey(environment, matchedVaultKey); if (v1VaultKey) { const v1Token = environment.config.tokens[v1VaultKey]; if (v1Token?.address) { fetchAddress = v1Token.address; } } } const lunarIndexerUrl = environment.lunarIndexerUrl; if (!lunarIndexerUrl) { return []; } try { const snapshots = await fetchVaultSnapshotsFromLunarIndexer( fetchAddress, environment.chainId, lunarIndexerUrl, period, customStartTime, customEndTime, ); // Restore the originally-requested vault address on every snapshot so // callers keying by address see the V2 address they asked for. if (fetchAddress.toLowerCase() !== requestedVaultAddress.toLowerCase()) { return snapshots.map((s) => ({ ...s, vaultAddress: requestedVaultAddress.toLowerCase(), })); } return snapshots; } catch (error) { console.warn( `[getMorphoVaultSnapshots] Lunar Indexer failed for chain ${environment.chainId}:`, error, ); environment.onError?.(error, { source: "morpho-vault-snapshots", chainId: environment.chainId, }); return []; } } async function fetchVaultSnapshotsFromLunarIndexer( vaultAddress: string, chainId: number, lunarIndexerUrl: string, period?: "1M" | "3M" | "1Y" | "ALL", customStartTime?: number, customEndTime?: number, ): Promise<MorphoVaultSnapshot[]> { const vaultId = `${chainId}-${vaultAddress.toLowerCase()}`; const allSnapshots: MorphoVaultSnapshot[] = []; let cursor: string | null = null; const MAX_PAGES = 100; let page = 0; const { startTime, endTime, granularity } = calculateTimeRange( period, customStartTime, customEndTime, ); do { const response = await fetchVaultSnapshotsFromIndexer( lunarIndexerUrl, vaultId, { limit: 1000, granularity: toApiGranularity(granularity), startTime, endTime, ...(cursor && { cursor }), }, ); const transformed = transformVaultSnapshotsFromIndexer( response.results, chainId, ); allSnapshots.push(...transformed); cursor = response.nextCursor; page++; } while (cursor !== null && page < MAX_PAGES); allSnapshots.sort((a, b) => a.timestamp - b.timestamp); return applyGranularity(allSnapshots, granularity); }