Add available HLS Vaults page (#558)

This commit is contained in:
Bob van der Helm 2023-10-18 12:23:47 +02:00 committed by GitHub
parent ccc4a42354
commit 63994ba87b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 306 additions and 172 deletions

View File

@ -1,34 +0,0 @@
import { getCreditManagerQueryClient } from 'api/cosmwasm-client'
import getAssetParams from 'api/params/getAssetParams'
import { getVaultConfigs } from 'api/vaults/getVaultConfigs'
import { BN } from 'utils/helpers'
import { resolveHLSStrategies } from 'utils/resolvers'
export default async function getHLSVaults() {
const assetParams = await getAssetParams()
const client = await getCreditManagerQueryClient()
const vaultConfigs = await getVaultConfigs()
const HLSAssets = assetParams.filter((asset) => asset.credit_manager.hls)
const strategies = resolveHLSStrategies('vault', HLSAssets)
const vaultUtilizations$ = strategies.map((strategy) =>
client.vaultUtilization({ vault: { address: strategy.denoms.deposit } }),
)
return Promise.all(vaultUtilizations$).then((vaultUtilizations) =>
vaultUtilizations.map(
(utilization, index) =>
({
...strategies[index],
depositCap: {
denom: utilization.vault.address,
used: BN(utilization.utilization.amount),
max: BN(
vaultConfigs.find((config) => config.addr === utilization.vault.address)?.deposit_cap
.amount || 0,
),
},
}) as HLSStrategy,
),
)
}

View File

@ -1,3 +1,4 @@
import getAssetParams from 'api/params/getAssetParams'
import getAprs from 'api/vaults/getVaultAprs'
import { getVaultConfigs } from 'api/vaults/getVaultConfigs'
import { getVaultUtilizations } from 'api/vaults/getVaultUtilizations'
@ -6,13 +7,17 @@ import { TESTNET_VAULTS_META_DATA, VAULTS_META_DATA } from 'constants/vaults'
import { NETWORK } from 'types/enums/network'
import { BN } from 'utils/helpers'
import { convertAprToApy } from 'utils/parsers'
import { resolveHLSStrategies } from 'utils/resolvers'
export default async function getVaults(): Promise<Vault[]> {
const assetParams = await getAssetParams()
const vaultConfigs = await getVaultConfigs()
const $vaultUtilizations = getVaultUtilizations(vaultConfigs)
const $aprs = getAprs()
const vaultMetaDatas =
ENV.NETWORK === NETWORK.TESTNET ? TESTNET_VAULTS_META_DATA : VAULTS_META_DATA
const HLSAssets = assetParams.filter((asset) => asset.credit_manager.hls)
const hlsStrategies = resolveHLSStrategies('vault', HLSAssets)
const vaults: Vault[] = []
await Promise.all([$vaultUtilizations, $aprs]).then(([vaultUtilizations, aprs]) => {
@ -43,6 +48,17 @@ export default async function getVaults(): Promise<Vault[]> {
},
}
const hlsStrategy = hlsStrategies.find(
(strategy) => strategy.denoms.deposit === vaultConfig.addr,
)
if (hlsStrategy) {
vault.hls = {
maxLTV: hlsStrategy.maxLTV,
maxLeverage: hlsStrategy.maxLeverage,
borrowDenom: hlsStrategy.denoms.borrow,
}
}
vaults.push(vault)
})
})

View File

@ -3,7 +3,6 @@ import { Table as TanstackTable } from '@tanstack/table-core/build/lib/types'
import React, { useCallback } from 'react'
import useAvailableColumns from 'components/Borrow/Table/Columns/useAvailableColumns'
import Card from 'components/Card'
import MarketDetails from 'components/MarketDetails'
import Table from 'components/Table'
@ -28,13 +27,12 @@ export default function AvailableBorrowingsTable(props: Props) {
if (!props.data.length) return null
return (
<Card className='w-full h-fit bg-white/5' title={'Available to Borrow'}>
<Table
title='Available to Borrow'
columns={columns}
data={props.data}
initialSorting={[{ id: 'asset.name', desc: true }]}
renderExpanded={renderExpanded}
/>
</Card>
)
}

View File

@ -3,7 +3,6 @@ import { Table as TanStackTable } from '@tanstack/table-core/build/lib/types'
import React, { useCallback } from 'react'
import useDepositedColumns from 'components/Borrow/Table/Columns/useDepositedColumns'
import Card from 'components/Card'
import MarketDetails from 'components/MarketDetails'
import Table from 'components/Table'
@ -26,13 +25,12 @@ export default function DepositedBorrowingsTable(props: Props) {
if (!props.data.length) return null
return (
<Card className='w-full h-fit bg-white/5' title='Borrowed Assets'>
<Table
title='Borrowed Assets'
columns={columns}
data={props.data}
initialSorting={[{ id: 'asset.name', desc: true }]}
renderExpanded={renderExpanded}
/>
</Card>
)
}

View File

@ -1,6 +1,5 @@
import React from 'react'
import Card from 'components/Card'
import useAvailableColumns from 'components/Earn/Farm/Table/Columns/useAvailableColumns'
import Table from 'components/Table'
@ -13,8 +12,11 @@ export default function AvailableVaultsTable(props: Props) {
const columns = useAvailableColumns({ isLoading: props.isLoading })
return (
<Card className='w-full h-fit bg-white/5' title={'Available vaults'}>
<Table columns={columns} data={props.data} initialSorting={[{ id: 'name', desc: true }]} />
</Card>
<Table
title='Available vaults'
columns={columns}
data={props.data}
initialSorting={[{ id: 'name', desc: true }]}
/>
)
}

View File

@ -7,7 +7,7 @@ import TitleAndSubCell from 'components/TitleAndSubCell'
import { VaultStatus } from 'types/enums/vault'
import { produceCountdown } from 'utils/formatters'
export const NAME_META = { header: 'Vault', accessorKey: 'name' }
export const NAME_META = { id: 'name', header: 'Vault', accessorKey: 'name' }
interface Props {
vault: Vault | DepositedVault
}

View File

@ -2,7 +2,6 @@ import { Row } from '@tanstack/react-table'
import { Table as TanStackTable } from '@tanstack/table-core/build/lib/types'
import React, { useCallback } from 'react'
import Card from 'components/Card'
import useDepositedColumns from 'components/Earn/Farm/Table/Columns/useDepositedColumns'
import VaultExpanded from 'components/Earn/Farm/VaultExpanded'
import Table from 'components/Table'
@ -23,13 +22,12 @@ export default function DepositedVaultsTable(props: Props) {
)
return (
<Card className='w-full h-fit bg-white/5' title={'Deposited vaults'}>
<Table
title='Deposited Vaults'
columns={columns}
data={props.data}
initialSorting={[{ id: 'name', desc: true }]}
renderExpanded={renderExpanded}
/>
</Card>
)
}

View File

@ -1,13 +1,11 @@
import { Row } from '@tanstack/react-table'
import React, { useCallback } from 'react'
import Card from 'components/Card'
import { NAME_META } from 'components/Earn/Lend/Table/Columns/Name'
import useAvailableColumns from 'components/Earn/Lend/Table/Columns/useAvailableColumns'
import MarketDetails from 'components/MarketDetails'
import Table from 'components/Table'
import MarketDetails from '../../../MarketDetails'
type Props = {
data: LendingMarketTableData[]
isLoading: boolean
@ -24,13 +22,12 @@ export default function AvailableLendsTable(props: Props) {
if (!props.data.length) return null
return (
<Card className='w-full h-fit bg-white/5' title={'Available Markets'}>
<Table
title='Available Markets'
columns={columns}
data={props.data}
initialSorting={[{ id: NAME_META.id, desc: true }]}
renderExpanded={renderExpanded}
/>
</Card>
)
}

View File

@ -1,7 +1,6 @@
import { Row } from '@tanstack/react-table'
import React, { useCallback } from 'react'
import Card from 'components/Card'
import { NAME_META } from 'components/Earn/Lend/Table/Columns/Name'
import useDepositedColumns from 'components/Earn/Lend/Table/Columns/useDepositedColumns'
import MarketDetails from 'components/MarketDetails'
@ -23,13 +22,12 @@ export default function DepositedLendsTable(props: Props) {
if (!props.data.length) return null
return (
<Card className='w-full h-fit bg-white/5' title={'Lent Assets'}>
<Table
title='Lent Assets'
columns={columns}
data={props.data}
initialSorting={[{ id: NAME_META.id, desc: true }]}
renderExpanded={renderExpanded}
/>
</Card>
)
}

View File

@ -1,3 +1,64 @@
export default function AvailableHlsVaults() {
return null
import { Suspense, useMemo } from 'react'
import { NAME_META } from 'components/Earn/Farm/Table/Columns/Name'
import Table from 'components/Table'
import { ENV } from 'constants/env'
import { BN_ZERO } from 'constants/math'
import { TESTNET_VAULTS_META_DATA, VAULTS_META_DATA } from 'constants/vaults'
import useVaults from 'hooks/useVaults'
import { NETWORK } from 'types/enums/network'
import useAvailableColumns from './Table/Columns/useAvailableColumns'
const title = 'Available HLS Vaults'
function Content() {
const { data: vaults } = useVaults()
const hlsVaults: Vault[] = useMemo(() => vaults?.filter((vault) => vault.hls) || [], [vaults])
const columns = useAvailableColumns({ isLoading: false })
return (
<Table
title={title}
columns={columns}
data={hlsVaults}
initialSorting={[{ id: NAME_META.id, desc: true }]}
/>
)
}
export default function AvailableHlsVaults() {
return (
<Suspense fallback={<Fallback />}>
<Content />
</Suspense>
)
}
function Fallback() {
const columns = useAvailableColumns({ isLoading: true })
const vaults = ENV.NETWORK === NETWORK.TESTNET ? TESTNET_VAULTS_META_DATA : VAULTS_META_DATA
const mockVaults: Vault[] = vaults.map((vault) => ({
...vault,
apy: null,
apr: null,
ltv: {
max: 0,
liq: 0,
},
cap: {
denom: 'denom',
used: BN_ZERO,
max: BN_ZERO,
},
}))
return (
<Table
title={title}
columns={columns}
data={mockVaults}
initialSorting={[{ id: NAME_META.id, desc: true }]}
/>
)
}

View File

@ -0,0 +1,40 @@
import React from 'react'
import { FormattedNumber } from 'components/FormattedNumber'
import Loading from 'components/Loading'
import useMarketBorrowings from 'hooks/useMarketBorrowings'
export const APY_META = { accessorKey: 'apy', header: 'APY Range' }
interface Props {
vault: Vault
}
export default function Apy(props: Props) {
const { vault } = props
const { data: marketBorrowings } = useMarketBorrowings()
const borrowRate = marketBorrowings.find((asset) => asset.denom === vault.hls?.borrowDenom)
?.borrowRate
if (vault.apy === null || borrowRate === null) return <Loading />
const APYs = [vault.apy, vault.apy * (vault.hls?.maxLeverage || 1) - (borrowRate || 0) * 100]
return (
<>
<FormattedNumber
amount={Math.min(...APYs)}
options={{ minDecimals: 2, maxDecimals: 2, suffix: '-' }}
className='text-xs inline'
animate
/>
<FormattedNumber
amount={Math.max(...APYs)}
options={{ minDecimals: 2, maxDecimals: 2, suffix: '%' }}
className='text-xs inline'
animate
/>
</>
)
}

View File

@ -0,0 +1,27 @@
import React from 'react'
import ActionButton from 'components/Button/ActionButton'
import Loading from 'components/Loading'
export const DEPOSIT_META = { accessorKey: 'deposit', header: 'Deposit' }
interface Props {
vault: Vault
isLoading: boolean
}
export default function Deposit(props: Props) {
const { vault } = props
function enterVaultHandler() {
return
}
if (props.isLoading) return <Loading />
return (
<div className='flex items-center justify-end'>
<ActionButton onClick={enterVaultHandler} color='tertiary' text='Deposit' />
</div>
)
}

View File

@ -0,0 +1,19 @@
import React from 'react'
import { FormattedNumber } from 'components/FormattedNumber'
export const MAX_LEV_META = { accessorKey: 'hls.maxLeverage', header: 'Max Leverage' }
interface Props {
vault: Vault
}
export default function MaxLeverage(props: Props) {
return (
<FormattedNumber
amount={props.vault.hls?.maxLeverage || 1}
options={{ minDecimals: 2, maxDecimals: 2, suffix: 'x' }}
className='text-xs'
animate
/>
)
}

View File

@ -1,19 +0,0 @@
import React from 'react'
import TitleAndSubCell from 'components/TitleAndSubCell'
interface Props {
strategy: HLSStrategy
}
export default function Name(props: Props) {
return (
<div className='flex'>
<TitleAndSubCell
className='ml-2 mr-2 text-left'
title={`${props.strategy.denoms.deposit}-${props.strategy.denoms.borrow}`}
sub={'Via Mars'}
/>
</div>
)
}

View File

@ -1,17 +1,51 @@
import { ColumnDef } from '@tanstack/react-table'
import { useMemo } from 'react'
import React, { useMemo } from 'react'
import Name from 'components/HLS/Farm/Table/Columns/Name'
import DepositCap, { DEPOSIT_CAP_META } from 'components/Earn/Farm/Table/Columns/DepositCap'
import MaxLTV, { LTV_MAX_META } from 'components/Earn/Farm/Table/Columns/MaxLTV'
import Name, { NAME_META } from 'components/Earn/Farm/Table/Columns/Name'
import TVL, { TVL_META } from 'components/Earn/Farm/Table/Columns/TVL'
import Apy, { APY_META } from 'components/HLS/Farm/Table/Columns/APY'
import Deposit, { DEPOSIT_META } from 'components/HLS/Farm/Table/Columns/Deposit'
import MaxLeverage, { MAX_LEV_META } from 'components/HLS/Farm/Table/Columns/MaxLeverage'
export default function useAvailableColumns() {
return useMemo<ColumnDef<HLSStrategy>[]>(
interface Props {
isLoading: boolean
}
export default function useAvailableColumns(props: Props) {
// const
return useMemo<ColumnDef<Vault>[]>(
() => [
{
header: 'Vault',
accessorKey: 'name',
cell: ({ row }) => <Name strategy={row.original} />,
...NAME_META,
cell: ({ row }) => <Name vault={row.original as Vault} />,
},
{
...APY_META,
cell: ({ row }) => <Apy vault={row.original as Vault} />,
},
{
...MAX_LEV_META,
cell: ({ row }) => <MaxLeverage vault={row.original} />,
},
{
...TVL_META,
cell: ({ row }) => <TVL vault={row.original as Vault} isLoading={props.isLoading} />,
},
{
...DEPOSIT_CAP_META,
cell: ({ row }) => <DepositCap vault={row.original as Vault} isLoading={props.isLoading} />,
},
{
...LTV_MAX_META,
cell: ({ row }) => <MaxLTV vault={row.original as Vault} isLoading={props.isLoading} />,
},
{
...DEPOSIT_META,
cell: ({ row }) => <Deposit vault={row.original as Vault} isLoading={props.isLoading} />,
},
],
[],
[props.isLoading],
)
}

View File

@ -11,11 +11,13 @@ import {
import classNames from 'classnames'
import React from 'react'
import Card from 'components/Card'
import { SortAsc, SortDesc, SortNone } from 'components/Icons'
import Row from 'components/Table/Row'
import Text from 'components/Text'
interface Props<T> {
title: string
columns: ColumnDef<T>[]
data: T[]
initialSorting: SortingState
@ -37,6 +39,7 @@ export default function Table<T>(props: Props<T>) {
})
return (
<Card className='w-full h-fit bg-white/5' title={props.title}>
<table className='w-full'>
<thead className='bg-black/20'>
{table.getHeaderGroups().map((headerGroup) => (
@ -88,5 +91,6 @@ export default function Table<T>(props: Props<T>) {
))}
</tbody>
</table>
</Card>
)
}

View File

@ -1,10 +0,0 @@
import useSWR from 'swr'
import getHLSVaults from 'api/hls/getHLSVaults'
export default function useHLSVaults() {
return useSWR('hls-vaults', getHLSVaults, {
fallbackData: [],
revalidateOnFocus: false,
})
}

View File

@ -33,6 +33,11 @@ interface VaultInfo {
interface VaultConfig extends VaultMetaData, VaultInfo {}
interface Vault extends VaultConfig {
hls?: {
maxLTV: number
maxLeverage: number
borrowDenom: string
}
apy: number | null
apr: number | null
}