UNPKG

@moonwell-fi/moonwell-sdk

Version:

TypeScript Interface for Moonwell

168 lines (146 loc) 5.01 kB
import { base } from "viem/chains"; import type { MoonwellClient } from "../../client/createMoonwellClient.js"; import { Amount, DAYS_PER_YEAR, SECONDS_PER_DAY, getEnvironmentsFromArgs, } from "../../common/index.js"; import type { NetworkParameterType } from "../../common/types.js"; import { type Chain, type Environment, type TokensType, publicEnvironments, } from "../../environments/index.js"; import type { StakingInfo } from "../../types/staking.js"; import { getMerklStakingApr } from "./common.js"; export type GetStakingInfoParameters< environments, network extends Chain | undefined, > = NetworkParameterType<environments, network>; export type GetStakingInfoReturnType = Promise<StakingInfo[]>; export async function getStakingInfo< environments, Network extends Chain | undefined, >( client: MoonwellClient, args?: GetStakingInfoParameters<environments, Network>, ): GetStakingInfoReturnType { const environments = getEnvironmentsFromArgs(client, args); const envsWithStaking = environments.filter( (env) => env.config.contracts.stakingToken, ); const envStakingInfoSettlements = await Promise.allSettled( envsWithStaking.map(async (environment) => { const homeEnvironment = (Object.values(publicEnvironments) as Environment[]).find((e) => e.custom?.governance?.chainIds?.includes(environment.chainId), ) || environment; const isBase = environment.chainId === base.id; const settlements = await Promise.allSettled([ environment.contracts.views?.read.getStakingInfo(), homeEnvironment.contracts.views?.read.getGovernanceTokenPrice(), ...(isBase ? [ environment.contracts.views?.read.getStakingInfo({ blockNumber: BigInt(34149943), }), ] : []), ]); return settlements.map((s) => s.status === "fulfilled" ? s.value : undefined, ); }), ); const envStakingInfo = envStakingInfoSettlements .filter((s) => s.status === "fulfilled") .map( (s) => ( s as PromiseFulfilledResult< ( | bigint | { cooldown: bigint; unstakeWindow: bigint; distributionEnd: bigint; totalSupply: bigint; emissionPerSecond: bigint; lastUpdateTimestamp: bigint; index: bigint; } | undefined )[] > ).value, ) .filter((val) => val !== undefined); const baseEnv = envsWithStaking.find((env) => env.chainId === base.id); const stakingTokenKey = baseEnv?.config.contracts.stakingToken; const baseStkToken = baseEnv != null && stakingTokenKey != null ? baseEnv.config.tokens[stakingTokenKey] : undefined; const baseStakingApr = baseStkToken != null ? await getMerklStakingApr(baseStkToken.address) : 0; const result = envsWithStaking.flatMap((curr, index) => { const token = curr.config.tokens[ curr.config.contracts.governanceToken as keyof TokensType<typeof curr> ]!; const stakingToken = curr.config.tokens[ curr.config.contracts.stakingToken as keyof TokensType<typeof curr> ]!; const envStakingInfoData = envStakingInfo[index]![0]!; const envGovernanceTokenPriceData = envStakingInfo[index]![1]; const envStakingInfoDataAfterX28Proposal = envStakingInfo[index]![2]!; const isBase = curr.chainId === base.id; if ( !envStakingInfoData || (isBase && !envStakingInfoDataAfterX28Proposal) ) { return []; } const { cooldown, distributionEnd, emissionPerSecond: emissionPerSecondRaw, totalSupply: totalSupplyRaw, unstakeWindow, } = envStakingInfoData as { cooldown: bigint; distributionEnd: bigint; emissionPerSecond: bigint; totalSupply: bigint; unstakeWindow: bigint; }; //Quick workaround to get governance token price from some other environment const governanceTokenPrice = new Amount( (envGovernanceTokenPriceData ?? 0n) as bigint, 18, ); const totalSupply = new Amount(totalSupplyRaw, 18); const emissionPerSecond = new Amount(emissionPerSecondRaw, 18); const emissionPerYear = emissionPerSecond.value * SECONDS_PER_DAY * DAYS_PER_YEAR; const apr = ((emissionPerYear + totalSupply.value) / totalSupply.value - 1) * 100; const stakingInfo: StakingInfo = { apr: isBase ? baseStakingApr : apr, chainId: curr.chainId, cooldown: Number(cooldown), distributionEnd: Number(distributionEnd), token, tokenPrice: governanceTokenPrice.value, stakingToken, totalSupply, totalSupplyUSD: totalSupply.value * governanceTokenPrice.value, unstakeWindow: Number(unstakeWindow), }; return stakingInfo; }); return result; }