UNPKG

@moonwell-fi/moonwell-sdk

Version:

TypeScript Interface for Moonwell

168 lines (150 loc) 5.01 kB
import dayjs from "dayjs"; import utc from "dayjs/plugin/utc.js"; import type { MoonwellClient } from "../client/createMoonwellClient.js"; import type { Environment } from "../environments/index.js"; dayjs.extend(utc); export { Amount } from "./amount.js"; export { BaseError, HttpRequestError } from "./error.js"; export type { HttpRequestErrorType } from "./error.js"; export { getBlockNumberAtTimestamp } from "./getBlockNumberAtTimestamp.js"; export type { MultichainReturnType } from "./types.js"; export const SECONDS_PER_DAY = 86400; export const DAYS_PER_YEAR = 365; export const perDay = (value: number) => value * SECONDS_PER_DAY; export function isStartOfDay(timestamp: number): boolean { const startOfDay = dayjs .utc(timestamp * 1000) .startOf("day") .unix(); return startOfDay === timestamp; } export const calculateApy = (value: number) => ((value * SECONDS_PER_DAY + 1) ** DAYS_PER_YEAR - 1) * 100; export type SnapshotPeriod = "1M" | "3M" | "1Y" | "ALL"; export type SnapshotGranularity = "6h" | "1d" | "7d" | "14d" | "30d"; /** * Filter snapshots to keep every Nth data point based on granularity. * "6h" and "1d" are handled natively by the API — no client-side filtering applied. * Coarser granularities (7d, 14d, 30d) fetch "1d" from the API and thin here. * * Callers must sort snapshots ascending by timestamp before calling this function. * Always keeps index 0, N, 2N, … so the oldest data point is always retained. */ export function applyGranularity<T extends { timestamp: number }>( snapshots: T[], granularity: SnapshotGranularity, ): T[] { const step: Record<SnapshotGranularity, number> = { "6h": 1, "1d": 1, "7d": 7, "14d": 14, "30d": 30, }; const n = step[granularity]; if (n <= 1) return snapshots; return snapshots.filter((_, i) => i % n === 0); } /** * Map a SnapshotGranularity to the value passed to the lunar indexer API. * "6h" is natively supported; coarser granularities (7d, 14d, 30d) are not, * so we fetch "1d" and thin client-side via applyGranularity. */ export function toApiGranularity( granularity: SnapshotGranularity, ): "6h" | "1d" { return granularity === "6h" ? "6h" : "1d"; } /** * Calculate start/end times and display granularity based on period or custom timestamps. * Priority: custom timestamps > period > default (365 days) * * Granularity per period: * 1M → 6h (4 data points per day, API-native) * 3M → 1d (one data point per day) * 1Y → 7d (one data point every 7 days, client-side filtered) * ALL → 14d (one data point every 14 days, client-side filtered) */ export function calculateTimeRange( period?: SnapshotPeriod, startTime?: number, endTime?: number, ): { startTime: number; endTime: number; granularity: SnapshotGranularity } { const now = dayjs.utc(); const end = endTime ?? now.unix(); if (startTime !== undefined) { return { startTime, endTime: end, granularity: "1d" }; } let start: number; let granularity: SnapshotGranularity; switch (period) { case "1M": start = now.subtract(31, "days").unix(); granularity = "6h"; break; case "3M": start = now.subtract(91, "days").unix(); granularity = "1d"; break; case "1Y": start = now.subtract(366, "days").unix(); granularity = "7d"; break; case "ALL": start = now.subtract(3, "years").unix(); granularity = "14d"; break; case undefined: start = now.subtract(366, "days").unix(); granularity = "1d"; break; } return { startTime: start, endTime: end, granularity }; } export const getEnvironmentFromArgs = ( client: MoonwellClient, args?: { chainId?: number; network?: any }, ) => { if (args) { const { chainId, network } = args as { chainId?: number; network?: keyof typeof client.environments; }; if (chainId) { return Object.values(client.environments).find( (env) => env.chainId === chainId, ) as Environment; } if (network) { return client.environments[network] as Environment; } } return undefined; }; export const getEnvironmentsFromArgs = ( client: MoonwellClient, args?: { chainId?: number; network?: any }, onlyWithDeployment?: boolean, ): Environment[] => { const onlyEnvironmentsWithDeployment = onlyWithDeployment !== undefined ? onlyWithDeployment : true; if (args) { const { chainId, network } = args as { chainId?: number; network?: keyof typeof client.environments; }; if (Number.isInteger(chainId)) { return [ Object.values(client.environments).find( (env) => env.chainId === chainId, ), ] as Environment[]; } if (network) { return [client.environments[network]] as Environment[]; } } return Object.values(client.environments as Environment[]).filter((r) => onlyEnvironmentsWithDeployment ? r.contracts.views !== undefined : true, ); };