UNPKG

@moonwell-fi/moonwell-sdk

Version:

TypeScript Interface for Moonwell

273 lines 10.4 kB
import axios from "axios"; import dayjs from "dayjs"; import utc from "dayjs/plugin/utc.js"; import { Amount, getEnvironmentFromArgs, isStartOfDay, } from "../../../common/index.js"; import { getSubgraph } from "../../morpho/utils/graphql.js"; dayjs.extend(utc); export async function getMarketSnapshots(client, args) { const environment = getEnvironmentFromArgs(client, args); if (!environment) { return []; } if (args?.type === "core") { return fetchCoreMarketSnapshots(args.marketId, environment); } else { if (environment.custom.morpho?.minimalDeployment === false) { return fetchIsolatedMarketSnapshots(args.marketId, environment); } else { return fetchIsolatedMarketSnapshotsSubgraph(args.marketId, environment); } } } async function fetchCoreMarketSnapshots(marketAddress, environment) { const dailyData = []; let hasNextPage = true; let endCursor; while (hasNextPage) { const result = await axios.post(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) => isStartOfDay(f.timestamp))); hasNextPage = result.data.data.marketDailySnapshots.pageInfo.hasNextPage; endCursor = result.data.data.marketDailySnapshots.pageInfo.endCursor; } if (dailyData.length > 0) { 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; const result = { marketId: marketAddress.toLowerCase(), chainId: environment.chainId, timestamp: point.timestamp * 1000, totalSupply: supplied, totalSupplyUsd: suppliedUsd, totalBorrows: borrow, totalBorrowsUsd: borrowUsd, totalLiquidity: liquidity, totalLiquidityUsd: liquidityUsd, baseSupplyApy: point.baseSupplyApy, baseBorrowApy: point.baseBorrowApy, collateralTokenPrice: price, loanTokenPrice: price, }; return result; }); } else { return []; } } async function fetchMorphoGraphQL(query, operationName, variables) { try { const response = await axios.post("https://blue-api.morpho.org/graphql", { query: query, operationName, variables }, { timeout: 5000 }); if (response.status !== 200 || response.data.errors) { console.log(`Non-200 (${response.statusText} }) or other error from Morpho GraphQL! - ${JSON.stringify(response.data)}`); return undefined; } return response.data.data; } catch (error) { return undefined; } } async function fetchIsolatedMarketSnapshots(marketAddress, environment) { const operationName = "getMarketTotalTimeseries"; const variables = { options: { startTimestamp: dayjs.utc().subtract(1, "year").unix(), interval: "DAY", }, }; const query = ` query getMarketTotalTimeseries($options: TimeseriesOptions) { marketTotalTimeseries: marketByUniqueKey( chainId: ${environment.chainId} uniqueKey: "${marketAddress.toLowerCase()}" ) { uniqueKey loanAsset { priceUsd decimals } collateralAsset { priceUsd decimals } historicalState { supplyApy(options: $options) { x y } borrowApy(options: $options) { x y } borrowAssets(options: $options) { x y } borrowAssetsUsd(options: $options) { x y } supplyAssets(options: $options) { x y } supplyAssetsUsd(options: $options) { x y } liquidityAssets(options: $options) { x y } liquidityAssetsUsd(options: $options) { x y } } } }`; const result = await fetchMorphoGraphQL(query, operationName, variables); if (result) { try { const markets = result.marketTotalTimeseries.historicalState.borrowAssets.map((borrowAssets, index) => { const loanDecimals = result.marketTotalTimeseries.loanAsset.decimals; const borrowAssetsUsd = result.marketTotalTimeseries.historicalState.borrowAssetsUsd[index]; const supplyAssets = result.marketTotalTimeseries.historicalState.supplyAssets[index]; const supplyAssetsUsd = result.marketTotalTimeseries.historicalState.supplyAssetsUsd[index]; const liquidityAssets = result.marketTotalTimeseries.historicalState.liquidityAssets[index]; const liquidityAssetsUsd = result.marketTotalTimeseries.historicalState.liquidityAssetsUsd[index]; const supplyApy = result.marketTotalTimeseries.historicalState.supplyApy[index]; const borrowApy = result.marketTotalTimeseries.historicalState.borrowApy[index]; const collateralTokenPrice = result.marketTotalTimeseries.collateralAsset.priceUsd; const loanTokenPrice = result.marketTotalTimeseries.loanAsset.priceUsd; const totalSupply = (new Amount(BigInt(supplyAssets.y), Number(loanDecimals)).value * loanTokenPrice) / collateralTokenPrice; const totalBorrows = new Amount(BigInt(borrowAssets.y), Number(loanDecimals)).value; const totalLiquidity = (new Amount(BigInt(liquidityAssets.y), Number(loanDecimals)) .value * loanTokenPrice) / collateralTokenPrice; return { chainId: environment.chainId, timestamp: borrowAssets.x * 1000, marketId: marketAddress.toLowerCase(), totalBorrows, totalBorrowsUsd: Number(borrowAssetsUsd.y), totalSupply, totalSupplyUsd: Number(supplyAssetsUsd.y), totalLiquidity, totalLiquidityUsd: Number(liquidityAssetsUsd.y), baseSupplyApy: supplyApy.y, baseBorrowApy: borrowApy.y, loanTokenPrice, collateralTokenPrice, }; }); return markets; } catch (ex) { return []; } } else { return []; } } async function fetchIsolatedMarketSnapshotsSubgraph(marketAddress, environment) { const query = ` { marketDailySnapshots (where:{market:"${marketAddress.toLowerCase()}"}, orderBy:timestamp, orderDirection:desc, first: 365) { market { maximumLTV inputToken { decimals } borrowedToken { decimals } } variableBorrowedTokenBalance outputTokenPriceUSD inputTokenPriceUSD inputTokenBalance timestamp } } `; const result = await getSubgraph(environment, query); if (result) { try { const markets = result.marketDailySnapshots.map((item) => { const supplyDecimals = item.market.borrowedToken.decimals; const supplyAssets = item.inputTokenBalance; const totalSupplyInLoanToken = new Amount(BigInt(supplyAssets), Number(supplyDecimals)).value; const totalSupply = totalSupplyInLoanToken / Number(item.inputTokenPriceUSD); const borrowAssets = item.variableBorrowedTokenBalance; const totalBorrows = new Amount(BigInt(borrowAssets), Number(supplyDecimals)).value; const totalLiquidityInLoanToken = Math.max(totalSupplyInLoanToken - totalBorrows, 0); const totalLiquidity = totalLiquidityInLoanToken / Number(item.inputTokenPriceUSD); return { chainId: environment.chainId, timestamp: item.timestamp * 1000, marketId: marketAddress.toLowerCase(), totalBorrows, totalBorrowsUsd: Number(item.outputTokenPriceUSD) * totalBorrows, totalSupply, totalSupplyUsd: Number(item.inputTokenPriceUSD) * totalSupply, totalLiquidity, totalLiquidityUsd: Number(item.outputTokenPriceUSD) * totalLiquidityInLoanToken, baseSupplyApy: 0, baseBorrowApy: 0, loanTokenPrice: Number(item.outputTokenPriceUSD), collateralTokenPrice: Number(item.inputTokenPriceUSD), }; }); return markets; } catch (ex) { return []; } } else { return []; } } //# sourceMappingURL=getMarketSnapshots.js.map