Mp 2539 vaults api (#156)
* add basic endpoint for vaultConfigs * implement apy for vaults
This commit is contained in:
parent
51543504f9
commit
4847121180
@ -3,8 +3,11 @@ import { Suspense } from 'react'
|
||||
import Card from 'components/Card'
|
||||
import Loading from 'components/Loading'
|
||||
import { Text } from 'components/Text'
|
||||
import { getVaults } from 'utils/api'
|
||||
|
||||
async function Content(props: PageProps) {
|
||||
const vaults = await getVaults()
|
||||
|
||||
const address = props.params.address
|
||||
|
||||
if (!address)
|
||||
|
38
src/constants/vaults.ts
Normal file
38
src/constants/vaults.ts
Normal file
@ -0,0 +1,38 @@
|
||||
export const VAULTS: VaultMetaData[] = [
|
||||
{
|
||||
address: 'osmo108q2krqr0y9g0rtesenvsw68sap2xefelwwjs0wedyvdl0cmrntqvllfjk',
|
||||
name: 'OSMO-ATOM',
|
||||
lockup: {
|
||||
duration: 14,
|
||||
timeframe: 'day',
|
||||
},
|
||||
provider: 'Apollo',
|
||||
denoms: {
|
||||
primary: 'uosmo',
|
||||
secondary: 'ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2',
|
||||
lp: 'gamm/pool/1',
|
||||
},
|
||||
symbols: {
|
||||
primary: 'OSMO',
|
||||
secondary: 'ATOM',
|
||||
},
|
||||
},
|
||||
{
|
||||
address: 'osmo1g5hryv0gp9dzlchkp3yxk8fmcf5asjun6cxkvyffetqzkwmvy75qfmeq3f',
|
||||
name: 'OSMO - JUNO',
|
||||
lockup: {
|
||||
duration: 14,
|
||||
timeframe: 'day',
|
||||
},
|
||||
provider: 'Apollo',
|
||||
denoms: {
|
||||
primary: 'uosmo',
|
||||
secondary: 'ibc/46B44899322F3CD854D2D46DEEF881958467CDD4B3B10086DA49296BBED94BED',
|
||||
lp: 'gamm/pool/497',
|
||||
},
|
||||
symbols: {
|
||||
primary: 'OSMO',
|
||||
secondary: 'JUNO',
|
||||
},
|
||||
},
|
||||
]
|
@ -2,6 +2,12 @@ import { CosmWasmClient } from '@cosmjs/cosmwasm-stargate'
|
||||
import { NextApiRequest, NextApiResponse } from 'next'
|
||||
|
||||
import { ENV, ENV_MISSING_MESSAGE } from 'constants/env'
|
||||
import {
|
||||
ArrayOfVaultInfoResponse,
|
||||
VaultBaseForString,
|
||||
} from 'types/generated/mars-credit-manager/MarsCreditManager.types'
|
||||
import { VAULTS } from 'constants/vaults'
|
||||
import { convertAprToApy } from 'utils/parsers'
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
if (!ENV.URL_RPC || !ENV.ADDRESS_CREDIT_MANAGER) {
|
||||
@ -9,13 +15,127 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
}
|
||||
const client = await CosmWasmClient.connect(ENV.URL_RPC)
|
||||
|
||||
const data = await client.queryContractSmart(ENV.ADDRESS_CREDIT_MANAGER, {
|
||||
vaults_info: { limit: 5, start_after: undefined },
|
||||
const $vaultConfigs = getVaultConfigs(client)
|
||||
const $aprs = getAprs()
|
||||
const vaults: Vault[] = await Promise.all([$vaultConfigs, $aprs]).then(([vaultConfigs, aprs]) => {
|
||||
return vaultConfigs.map((vaultConfig) => {
|
||||
const apr = aprs.find((apr) => apr.address === vaultConfig.address)
|
||||
if (apr) {
|
||||
return {
|
||||
...vaultConfig,
|
||||
apy: convertAprToApy(apr.apr, 365),
|
||||
}
|
||||
}
|
||||
return {
|
||||
...vaultConfig,
|
||||
apy: null,
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
if (data) {
|
||||
return res.status(200).json(data)
|
||||
if (vaults) {
|
||||
return res.status(200).json(vaults)
|
||||
}
|
||||
|
||||
return res.status(404)
|
||||
}
|
||||
|
||||
async function getVaultConfigs(client: CosmWasmClient, startAfter?: VaultBaseForString) {
|
||||
let data: VaultConfig[] = []
|
||||
|
||||
const getBatch = async (startAfter?: VaultBaseForString) => {
|
||||
if (!ENV.ADDRESS_CREDIT_MANAGER) return
|
||||
|
||||
const batch: ArrayOfVaultInfoResponse = await client.queryContractSmart(
|
||||
ENV.ADDRESS_CREDIT_MANAGER,
|
||||
{
|
||||
vaults_info: { limit: 4, start_after: startAfter },
|
||||
},
|
||||
)
|
||||
|
||||
const batchProcessed = batch?.map((vaultInfo) => {
|
||||
return {
|
||||
address: vaultInfo.vault.address,
|
||||
cap: {
|
||||
denom: vaultInfo.config.deposit_cap.denom,
|
||||
used: Number(vaultInfo.utilization.amount),
|
||||
max: Number(vaultInfo.config.deposit_cap.amount),
|
||||
},
|
||||
ltv: {
|
||||
max: Number(vaultInfo.config.max_ltv),
|
||||
liq: Number(vaultInfo.config.liquidation_threshold),
|
||||
},
|
||||
} as VaultConfig
|
||||
})
|
||||
|
||||
data = [...data, ...batchProcessed]
|
||||
|
||||
if (batch.length === 4) {
|
||||
await getBatch({
|
||||
address: batchProcessed[batchProcessed.length - 1].address,
|
||||
} as VaultBaseForString)
|
||||
}
|
||||
}
|
||||
|
||||
await getBatch()
|
||||
|
||||
return VAULTS.map((vaultMetaData) => {
|
||||
const vaultInfo = data.find((vault) => vault.address === vaultMetaData.address)
|
||||
|
||||
return {
|
||||
...vaultMetaData,
|
||||
...vaultInfo,
|
||||
} as VaultConfig
|
||||
})
|
||||
}
|
||||
|
||||
interface FlatApr {
|
||||
contract_address: string
|
||||
apr: { type: string; value: number | string }[]
|
||||
fees: { type: string; value: number | string }[]
|
||||
}
|
||||
|
||||
interface NestedApr {
|
||||
contract_address: string
|
||||
apr: {
|
||||
aprs: { type: string; value: number | string }[]
|
||||
fees: { type: string; value: number | string }[]
|
||||
}
|
||||
}
|
||||
|
||||
async function getAprs() {
|
||||
const APOLLO_URL = 'https://api.apollo.farm/api/vault_infos/v2/osmo-test-4'
|
||||
|
||||
try {
|
||||
const response = await fetch(APOLLO_URL)
|
||||
|
||||
if (response.ok) {
|
||||
const data: FlatApr[] | NestedApr[] = await response.json()
|
||||
|
||||
const newAprs = data.map((aprData) => {
|
||||
try {
|
||||
const apr = aprData as FlatApr
|
||||
const aprTotal = apr.apr.reduce((prev, curr) => Number(curr.value) + prev, 0)
|
||||
const feeTotal = apr.fees.reduce((prev, curr) => Number(curr.value) + prev, 0)
|
||||
|
||||
const finalApr = aprTotal + feeTotal
|
||||
|
||||
return { address: aprData.contract_address, apr: finalApr }
|
||||
} catch {
|
||||
const apr = aprData as NestedApr
|
||||
const aprTotal = apr.apr.aprs.reduce((prev, curr) => Number(curr.value) + prev, 0)
|
||||
const feeTotal = apr.apr.fees.reduce((prev, curr) => Number(curr.value) + prev, 0)
|
||||
|
||||
const finalApr = aprTotal + feeTotal
|
||||
return { address: aprData.contract_address, apr: finalApr }
|
||||
}
|
||||
})
|
||||
|
||||
return newAprs
|
||||
}
|
||||
|
||||
return []
|
||||
} catch {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
34
src/types/interfaces/vaults.d.ts
vendored
Normal file
34
src/types/interfaces/vaults.d.ts
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
interface VaultMetaData {
|
||||
address: string
|
||||
name: string
|
||||
lockup: {
|
||||
duration: number
|
||||
timeframe: string
|
||||
}
|
||||
provider: string
|
||||
denoms: {
|
||||
primary: string
|
||||
secondary: string
|
||||
lp: string
|
||||
}
|
||||
symbols: {
|
||||
primary: string
|
||||
secondary: string
|
||||
}
|
||||
}
|
||||
|
||||
interface VaultConfig extends VaultMetaData {
|
||||
ltv: {
|
||||
max: number
|
||||
liq: number
|
||||
}
|
||||
cap: {
|
||||
denom: string
|
||||
used: numnber
|
||||
max: number
|
||||
}
|
||||
}
|
||||
|
||||
interface Vault extends VaultConfig {
|
||||
apy: number | null
|
||||
}
|
@ -9,6 +9,7 @@ export enum Endpoints {
|
||||
ACCOUNT_DEBTS = '/accounts/{accountId}/debts',
|
||||
MARKETS_BORROW = '/markets/borrow',
|
||||
PRICES = '/prices',
|
||||
VAULTS = '/vaults',
|
||||
WALLET_BALANCES = '/wallets/{address}/balances',
|
||||
}
|
||||
|
||||
@ -26,9 +27,12 @@ export function getEndpoint(endpoint: Endpoints, props?: ParamProps) {
|
||||
return returnEndpoint
|
||||
}
|
||||
|
||||
export async function callAPI<T>(endpoint: string): Promise<T> {
|
||||
export async function callAPI<T>(endpoint: string, cache?: RequestCache): Promise<T> {
|
||||
const response = await fetch(`${ENV.URL_API}${endpoint}${VERCEL_BYPASS}`, {
|
||||
cache: 'no-store',
|
||||
cache: cache ? cache : 'no-store',
|
||||
next: {
|
||||
revalidate: 30,
|
||||
},
|
||||
})
|
||||
|
||||
return response.json() as T
|
||||
@ -60,6 +64,10 @@ export async function getPrices() {
|
||||
return callAPI<Coin[]>(getEndpoint(Endpoints.PRICES))
|
||||
}
|
||||
|
||||
export async function getVaults() {
|
||||
return callAPI<Coin[]>(getEndpoint(Endpoints.VAULTS), 'default')
|
||||
}
|
||||
|
||||
export async function getWalletBalancesSWR(url: string) {
|
||||
return callAPI<Coin[]>(url)
|
||||
}
|
||||
|
@ -9,3 +9,7 @@ export function isNumber(value: unknown) {
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
export const convertAprToApy = (apr: number, numberOfCompoundingPeriods: number): number => {
|
||||
return ((1 + apr / 100 / numberOfCompoundingPeriods) ** numberOfCompoundingPeriods - 1) * 100
|
||||
}
|
||||
|
5
src/utils/vaults.ts
Normal file
5
src/utils/vaults.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { VAULTS } from 'constants/vaults'
|
||||
|
||||
export function getVaultMetaData(address: string) {
|
||||
return VAULTS.find((vault) => vault.address === address)
|
||||
}
|
Loading…
Reference in New Issue
Block a user