vault: separate aprs (#777)

This commit is contained in:
Bob van der Helm 2024-02-07 10:59:54 +01:00 committed by GitHub
parent ef9c353b6b
commit b2b8f93bc3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 136 additions and 68 deletions

View File

@ -1,31 +0,0 @@
import { aprsCache, aprsCacheResponse, cacheFn } from 'api/cache'
export default async function getAprs(chainConfig: ChainConfig) {
if (!chainConfig.farm) return []
try {
const response = await cacheFn(
() => fetch(chainConfig.endpoints.aprs.vaults),
aprsCacheResponse,
`${chainConfig.id}/aprsResponse`,
60,
)
if (response.ok) {
const data: AprResponse = await cacheFn(
() => response.json(),
aprsCache,
`${chainConfig.id}/aprs`,
60,
)
return data.vaults.map((aprData) => {
const finalApr = aprData.apr.projected_apr * 100
return { address: aprData.address, apr: finalApr } as Apr
})
}
return []
} catch {
return []
}
}

View File

@ -1,24 +1,20 @@
import getAssetParams from 'api/params/getAssetParams' import getAssetParams from 'api/params/getAssetParams'
import getAprs from 'api/vaults/getVaultAprs'
import { getVaultConfigs } from 'api/vaults/getVaultConfigs' import { getVaultConfigs } from 'api/vaults/getVaultConfigs'
import { getVaultUtilizations } from 'api/vaults/getVaultUtilizations' import { getVaultUtilizations } from 'api/vaults/getVaultUtilizations'
import { BN } from 'utils/helpers' import { BN } from 'utils/helpers'
import { convertAprToApy } from 'utils/parsers'
import { resolveHLSStrategies } from 'utils/resolvers' import { resolveHLSStrategies } from 'utils/resolvers'
export default async function getVaults(chainConfig: ChainConfig): Promise<Vault[]> { export default async function getVaults(chainConfig: ChainConfig): Promise<Vault[]> {
const assetParams = await getAssetParams(chainConfig) const assetParams = await getAssetParams(chainConfig)
const vaultConfigs = await getVaultConfigs(chainConfig) const vaultConfigs = await getVaultConfigs(chainConfig)
const $vaultUtilizations = getVaultUtilizations(chainConfig, vaultConfigs) const $vaultUtilizations = getVaultUtilizations(chainConfig, vaultConfigs)
const $aprs = getAprs(chainConfig)
const vaultMetaDatas = chainConfig.vaults const vaultMetaDatas = chainConfig.vaults
const HLSAssets = assetParams.filter((asset) => asset.credit_manager.hls) const HLSAssets = assetParams.filter((asset) => asset.credit_manager.hls)
const hlsStrategies = resolveHLSStrategies('vault', HLSAssets) const hlsStrategies = resolveHLSStrategies('vault', HLSAssets)
const vaults: Vault[] = [] const vaults: Vault[] = []
await Promise.all([$vaultUtilizations, $aprs]).then(([vaultUtilizations, aprs]) => { await $vaultUtilizations.then((vaultUtilizations) => {
return vaultConfigs.map((vaultConfig) => { return vaultConfigs.map((vaultConfig) => {
const apr = aprs.find((apr) => apr.address === vaultConfig.addr)
const vaultMetaData = vaultMetaDatas.find( const vaultMetaData = vaultMetaDatas.find(
(vaultMetaData) => vaultMetaData.address === vaultConfig.addr, (vaultMetaData) => vaultMetaData.address === vaultConfig.addr,
) )
@ -36,8 +32,6 @@ export default async function getVaults(chainConfig: ChainConfig): Promise<Vault
)?.utilization.amount || 0, )?.utilization.amount || 0,
), ),
}, },
apy: apr ? convertAprToApy(apr.apr, 365) : null,
apr: apr ? apr.apr : null,
ltv: { ltv: {
max: Number(vaultConfig.max_loan_to_value), max: Number(vaultConfig.max_loan_to_value),
liq: Number(vaultConfig.liquidation_threshold), liq: Number(vaultConfig.liquidation_threshold),

View File

@ -1,11 +1,13 @@
import classNames from 'classnames' import classNames from 'classnames'
import AssetRate from 'components/common/assets/AssetRate' import AssetRate from 'components/common/assets/AssetRate'
import Loading from 'components/common/Loading'
import Text from 'components/common/Text'
export const APY_META = { accessorKey: 'apy', header: 'APY', meta: { className: 'w-30' } } export const APY_META = { accessorKey: 'apy', header: 'APY', meta: { className: 'w-30' } }
interface Props { interface Props {
apy: number apy?: number | null
markets: Market[] markets: Market[]
denom: string denom: string
type: PositionType type: PositionType
@ -14,12 +16,16 @@ interface Props {
export default function Apr(props: Props) { export default function Apr(props: Props) {
const { markets, type, denom, apy } = props const { markets, type, denom, apy } = props
if (apy === undefined) return <Loading />
if (apy === null) return <Text size='xs'>N/A</Text>
if (apy === 0) if (apy === 0)
return ( return (
<p className={classNames('w-full text-xs text-right number', type === 'vault' && 'pb-4')}> <p className={classNames('w-full text-xs text-right number', type === 'vault' && 'pb-4')}>
&ndash; &ndash;
</p> </p>
) )
const isEnabled = const isEnabled =
markets.find((market) => market.asset.denom === props.denom)?.borrowEnabled ?? false markets.find((market) => market.asset.denom === props.denom)?.borrowEnabled ?? false

View File

@ -13,6 +13,7 @@ import { ORACLE_DENOM } from 'constants/oracle'
import useAllAssets from 'hooks/assets/useAllAssets' import useAllAssets from 'hooks/assets/useAllAssets'
import useHLSStakingAssets from 'hooks/useHLSStakingAssets' import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
import usePrices from 'hooks/usePrices' import usePrices from 'hooks/usePrices'
import useVaultAprs from 'hooks/vaults/useVaultAprs'
import useStore from 'store' import useStore from 'store'
import { BNCoin } from 'types/classes/BNCoin' import { BNCoin } from 'types/classes/BNCoin'
import { calculateAccountApr, getAccountPositionValues } from 'utils/accounts' import { calculateAccountApr, getAccountPositionValues } from 'utils/accounts'
@ -37,6 +38,7 @@ export default function AccountComposition(props: Props) {
const hasChanged = !!updatedAccount const hasChanged = !!updatedAccount
const { data: prices } = usePrices() const { data: prices } = usePrices()
const { data: hlsStrategies } = useHLSStakingAssets() const { data: hlsStrategies } = useHLSStakingAssets()
const { data: vaultAprs } = useVaultAprs()
const assets = useAllAssets() const assets = useAllAssets()
const data = useBorrowMarketAssetsTableData() const data = useBorrowMarketAssetsTableData()
const borrowAssetsData = useMemo(() => data?.allAssets || [], [data]) const borrowAssetsData = useMemo(() => data?.allAssets || [], [data])
@ -75,9 +77,19 @@ export default function AccountComposition(props: Props) {
prices, prices,
hlsStrategies, hlsStrategies,
assets, assets,
vaultAprs,
props.isHls, props.isHls,
), ),
[account, assets, borrowAssetsData, hlsStrategies, lendingAssetsData, prices, props.isHls], [
account,
assets,
borrowAssetsData,
hlsStrategies,
lendingAssetsData,
prices,
props.isHls,
vaultAprs,
],
) )
const updatedApr = useMemo( const updatedApr = useMemo(
() => () =>
@ -89,6 +101,7 @@ export default function AccountComposition(props: Props) {
prices, prices,
hlsStrategies, hlsStrategies,
assets, assets,
vaultAprs,
props.isHls, props.isHls,
) )
: BN_ZERO, : BN_ZERO,
@ -99,6 +112,7 @@ export default function AccountComposition(props: Props) {
prices, prices,
hlsStrategies, hlsStrategies,
assets, assets,
vaultAprs,
props.isHls, props.isHls,
], ],
) )

View File

@ -22,9 +22,10 @@ import useCurrentAccount from 'hooks/accounts/useCurrentAccount'
import useAllAssets from 'hooks/assets/useAllAssets' import useAllAssets from 'hooks/assets/useAllAssets'
import useLocalStorage from 'hooks/localStorage/useLocalStorage' import useLocalStorage from 'hooks/localStorage/useLocalStorage'
import useAccountId from 'hooks/useAccountId' import useAccountId from 'hooks/useAccountId'
import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
import useHealthComputer from 'hooks/useHealthComputer' import useHealthComputer from 'hooks/useHealthComputer'
import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
import usePrices from 'hooks/usePrices' import usePrices from 'hooks/usePrices'
import useVaultAprs from 'hooks/vaults/useVaultAprs'
import useStore from 'store' import useStore from 'store'
import { BNCoin } from 'types/classes/BNCoin' import { BNCoin } from 'types/classes/BNCoin'
import { import {
@ -38,6 +39,7 @@ export default function AccountDetailsController() {
const isHLS = useStore((s) => s.isHLS) const isHLS = useStore((s) => s.isHLS)
const { data: _, isLoading } = useAccounts('default', address) const { data: _, isLoading } = useAccounts('default', address)
const { data: accountIds } = useAccountIds(address, false, true) const { data: accountIds } = useAccountIds(address, false, true)
const accountId = useAccountId() const accountId = useAccountId()
const account = useCurrentAccount() const account = useCurrentAccount()
@ -59,6 +61,7 @@ function AccountDetails(props: Props) {
const { account } = props const { account } = props
const location = useLocation() const location = useLocation()
const { data: hlsStrategies } = useHLSStakingAssets() const { data: hlsStrategies } = useHLSStakingAssets()
const { data: vaultAprs } = useVaultAprs()
const [reduceMotion] = useLocalStorage<boolean>( const [reduceMotion] = useLocalStorage<boolean>(
LocalStorageKeys.REDUCE_MOTION, LocalStorageKeys.REDUCE_MOTION,
DEFAULT_SETTINGS.reduceMotion, DEFAULT_SETTINGS.reduceMotion,
@ -107,9 +110,19 @@ function AccountDetails(props: Props) {
prices, prices,
hlsStrategies, hlsStrategies,
assets, assets,
vaultAprs,
account.kind === 'high_levered_strategy', account.kind === 'high_levered_strategy',
), ),
[account, assets, borrowAssetsData, hlsStrategies, lendingAssetsData, prices, updatedAccount], [
account,
assets,
borrowAssetsData,
hlsStrategies,
lendingAssetsData,
prices,
updatedAccount,
vaultAprs,
],
) )
const isFullWidth = const isFullWidth =
location.pathname.includes('trade') || location.pathname.includes('trade') ||
@ -128,7 +141,7 @@ function AccountDetails(props: Props) {
data-testid='account-details' data-testid='account-details'
className={classNames( className={classNames(
accountDetailsExpanded ? 'right-4' : '-right-74', accountDetailsExpanded ? 'right-4' : '-right-74',
'w-94 flex items-start gap-4 absolute top-6', 'w-94 flex items-start gap-4 absolute top-6 z-2',
!reduceMotion && 'transition-all duration-500', !reduceMotion && 'transition-all duration-500',
)} )}
> >

View File

@ -12,6 +12,7 @@ import useAllAssets from 'hooks/assets/useAllAssets'
import useHealthComputer from 'hooks/useHealthComputer' import useHealthComputer from 'hooks/useHealthComputer'
import useHLSStakingAssets from 'hooks/useHLSStakingAssets' import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
import usePrices from 'hooks/usePrices' import usePrices from 'hooks/usePrices'
import useVaultAprs from 'hooks/vaults/useVaultAprs'
import useStore from 'store' import useStore from 'store'
import { calculateAccountApr, calculateAccountBalanceValue } from 'utils/accounts' import { calculateAccountApr, calculateAccountBalanceValue } from 'utils/accounts'
@ -27,6 +28,7 @@ export default function AccountStats(props: Props) {
const { data: account } = useAccount(accountId) const { data: account } = useAccount(accountId)
const { data: prices } = usePrices() const { data: prices } = usePrices()
const { data: hlsStrategies } = useHLSStakingAssets() const { data: hlsStrategies } = useHLSStakingAssets()
const { data: vaultAprs } = useVaultAprs()
const positionBalance = useMemo( const positionBalance = useMemo(
() => (!account ? null : calculateAccountBalanceValue(account, prices, assets)), () => (!account ? null : calculateAccountBalanceValue(account, prices, assets)),
@ -52,9 +54,10 @@ export default function AccountStats(props: Props) {
prices, prices,
hlsStrategies, hlsStrategies,
assets, assets,
vaultAprs,
account.kind === 'high_levered_strategy', account.kind === 'high_levered_strategy',
), ),
[account, assets, borrowAssetsData, hlsStrategies, lendingAssetsData, prices], [account, assets, borrowAssetsData, hlsStrategies, lendingAssetsData, prices, vaultAprs],
) )
const deleteAccountHandler = useCallback(() => { const deleteAccountHandler = useCallback(() => {

View File

@ -4,8 +4,8 @@ import { byDenom } from 'utils/array'
export function getVaultAccountStrategiesRow( export function getVaultAccountStrategiesRow(
vault: DepositedVault, vault: DepositedVault,
apy: number,
prices: BNCoin[], prices: BNCoin[],
apy?: number | null,
prev?: DepositedVault, prev?: DepositedVault,
): AccountStrategyRow { ): AccountStrategyRow {
const { name } = vault const { name } = vault
@ -17,7 +17,7 @@ export function getVaultAccountStrategiesRow(
.plus(previous.values.unlocked) .plus(previous.values.unlocked)
.plus(previous.values.unlocking) .plus(previous.values.unlocking)
if (totalLockedValue.isLessThan(totalValue)) { if (totalLockedValue.isLessThan(totalValue) && apy) {
apy = totalLockedValue.dividedBy(totalValue).times(apy).toNumber() apy = totalLockedValue.dividedBy(totalValue).times(apy).toNumber()
} }

View File

@ -2,6 +2,7 @@ import { useMemo } from 'react'
import { getVaultAccountStrategiesRow } from 'components/account/AccountStrategiesTable/functions' import { getVaultAccountStrategiesRow } from 'components/account/AccountStrategiesTable/functions'
import usePrices from 'hooks/usePrices' import usePrices from 'hooks/usePrices'
import useVaultAprs from 'hooks/vaults/useVaultAprs'
interface Props { interface Props {
account: Account account: Account
@ -11,17 +12,18 @@ interface Props {
export default function useAccountStategiesData(props: Props) { export default function useAccountStategiesData(props: Props) {
const { account, updatedAccount } = props const { account, updatedAccount } = props
const { data: prices } = usePrices() const { data: prices } = usePrices()
const { data: vaultAprs } = useVaultAprs()
return useMemo<AccountStrategyRow[]>(() => { return useMemo<AccountStrategyRow[]>(() => {
const usedAccount = updatedAccount ?? account const usedAccount = updatedAccount ?? account
const accountVaults = usedAccount?.vaults ?? [] const accountVaults = usedAccount?.vaults ?? []
return accountVaults.map((vault) => { return accountVaults.map((vault) => {
const apy = vault.apy ?? 0 const apy = vaultAprs.find((vaultApr) => vaultApr.address === vault.address)?.apy
const prevVault = updatedAccount const prevVault = updatedAccount
? account?.vaults.find((position) => position.name === vault.name) ? account?.vaults.find((position) => position.name === vault.name)
: vault : vault
return getVaultAccountStrategiesRow(vault, apy, prices, prevVault) return getVaultAccountStrategiesRow(vault, prices, apy, prevVault)
}) })
}, [account, updatedAccount, prices]) }, [updatedAccount, account, vaultAprs, prices])
} }

View File

@ -13,9 +13,10 @@ import { LocalStorageKeys } from 'constants/localStorageKeys'
import { BN_ZERO } from 'constants/math' import { BN_ZERO } from 'constants/math'
import useAllAssets from 'hooks/assets/useAllAssets' import useAllAssets from 'hooks/assets/useAllAssets'
import useLocalStorage from 'hooks/localStorage/useLocalStorage' import useLocalStorage from 'hooks/localStorage/useLocalStorage'
import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
import useHealthComputer from 'hooks/useHealthComputer' import useHealthComputer from 'hooks/useHealthComputer'
import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
import usePrices from 'hooks/usePrices' import usePrices from 'hooks/usePrices'
import useVaultAprs from 'hooks/vaults/useVaultAprs'
import useStore from 'store' import useStore from 'store'
import { calculateAccountApr, calculateAccountLeverage } from 'utils/accounts' import { calculateAccountApr, calculateAccountLeverage } from 'utils/accounts'
@ -36,6 +37,7 @@ export default function AccountSummary(props: Props) {
storageKey, storageKey,
defaultSetting, defaultSetting,
) )
const { data: vaultAprs } = useVaultAprs()
const { data: prices } = usePrices() const { data: prices } = usePrices()
const assets = useAllAssets() const assets = useAllAssets()
const updatedAccount = useStore((s) => s.updatedAccount) const updatedAccount = useStore((s) => s.updatedAccount)
@ -79,16 +81,18 @@ export default function AccountSummary(props: Props) {
prices, prices,
hlsStrategies, hlsStrategies,
assets, assets,
vaultAprs,
props.account.kind === 'high_levered_strategy', props.account.kind === 'high_levered_strategy',
), ),
[ [
updatedAccount,
props.account, props.account,
assets,
borrowAssetsData, borrowAssetsData,
hlsStrategies,
lendingAssetsData, lendingAssetsData,
prices, prices,
updatedAccount, hlsStrategies,
assets,
vaultAprs,
], ],
) )

View File

@ -1,5 +1,6 @@
import { FormattedNumber } from 'components/common/FormattedNumber' import { FormattedNumber } from 'components/common/FormattedNumber'
import Loading from 'components/common/Loading' import Loading from 'components/common/Loading'
import Text from 'components/common/Text'
export const APY_META = { accessorKey: 'apy', header: 'APY' } export const APY_META = { accessorKey: 'apy', header: 'APY' }
@ -10,7 +11,9 @@ interface Props {
export default function Apy(props: Props) { export default function Apy(props: Props) {
const { vault } = props const { vault } = props
if (vault.apy === null) return <Loading /> if (vault.apy === undefined) return <Loading />
if (vault.apy === null) return <Text size='xs'>N/A</Text>
return ( return (
<FormattedNumber <FormattedNumber
amount={vault.apy ?? 0} amount={vault.apy ?? 0}

View File

@ -8,12 +8,14 @@ import useAccountId from 'hooks/useAccountId'
import useChainConfig from 'hooks/useChainConfig' import useChainConfig from 'hooks/useChainConfig'
import useDepositedVaults from 'hooks/useDepositedVaults' import useDepositedVaults from 'hooks/useDepositedVaults'
import useVaults from 'hooks/useVaults' import useVaults from 'hooks/useVaults'
import useVaultAprs from 'hooks/vaults/useVaultAprs'
import { VaultStatus } from 'types/enums/vault' import { VaultStatus } from 'types/enums/vault'
function Content() { function Content() {
const accountId = useAccountId() const accountId = useAccountId()
const { data: vaults } = useVaults() const { data: vaults } = useVaults()
const { data: depositedVaults } = useDepositedVaults(accountId || '') const { data: depositedVaults } = useDepositedVaults(accountId || '')
const { data: vaultAprs } = useVaultAprs()
const chainConfig = useChainConfig() const chainConfig = useChainConfig()
const vaultMetaData = chainConfig.vaults const vaultMetaData = chainConfig.vaults
@ -23,18 +25,19 @@ function Content() {
if (!vaults) return prev if (!vaults) return prev
const vault = vaults.find((vault) => vault.address === curr.address) const vault = vaults.find((vault) => vault.address === curr.address)
const depositedVault = depositedVaults?.find((vault) => vault.address === curr.address) const depositedVault = depositedVaults?.find((vault) => vault.address === curr.address)
const apr = vaultAprs.find((vaultApr) => vaultApr.address === curr.address)!
if (depositedVault) { if (depositedVault) {
prev.deposited.push(depositedVault) prev.deposited.push({ ...depositedVault, ...apr })
} else if (vault) { } else if (vault) {
prev.available.push(vault) prev.available.push({ ...vault, ...apr })
} }
return prev return prev
}, },
{ deposited: [], available: [] }, { deposited: [], available: [] },
) )
}, [vaults, depositedVaults, vaultMetaData]) }, [vaultMetaData, vaults, depositedVaults, vaultAprs])
const unlockedVaults: DepositedVault[] = [] const unlockedVaults: DepositedVault[] = []

View File

@ -2,6 +2,7 @@ import React from 'react'
import { FormattedNumber } from 'components/common/FormattedNumber' import { FormattedNumber } from 'components/common/FormattedNumber'
import Loading from 'components/common/Loading' import Loading from 'components/common/Loading'
import Text from 'components/common/Text'
import useMarket from 'hooks/markets/useMarket' import useMarket from 'hooks/markets/useMarket'
export const APY_META = { accessorKey: 'apy', header: 'APY Range' } export const APY_META = { accessorKey: 'apy', header: 'APY Range' }
@ -14,7 +15,8 @@ export default function Apy(props: Props) {
const { vault } = props const { vault } = props
const borrowRate = useMarket(vault.hls?.borrowDenom || '')?.apy.borrow const borrowRate = useMarket(vault.hls?.borrowDenom || '')?.apy.borrow
if (vault.apy === null || borrowRate === null) return <Loading /> if (vault.apy === undefined || borrowRate === null) return <Loading />
if (vault.apy === null) return <Text size='xs'>N/A</Text>
const APYs = [vault.apy, vault.apy * (vault.hls?.maxLeverage || 1) - (borrowRate || 0) * 100] const APYs = [vault.apy, vault.apy * (vault.hls?.maxLeverage || 1) - (borrowRate || 0) * 100]

View File

@ -11,6 +11,7 @@ import useAllAssets from 'hooks/assets/useAllAssets'
import useHealthComputer from 'hooks/useHealthComputer' import useHealthComputer from 'hooks/useHealthComputer'
import useHLSStakingAssets from 'hooks/useHLSStakingAssets' import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
import usePrices from 'hooks/usePrices' import usePrices from 'hooks/usePrices'
import useVaultAprs from 'hooks/vaults/useVaultAprs'
import { getAccountSummaryStats } from 'utils/accounts' import { getAccountSummaryStats } from 'utils/accounts'
import { DEFAULT_PORTFOLIO_STATS } from 'utils/constants' import { DEFAULT_PORTFOLIO_STATS } from 'utils/constants'
@ -21,6 +22,7 @@ interface Props {
function Content(props: Props) { function Content(props: Props) {
const { data: account } = useAccount(props.accountId, true) const { data: account } = useAccount(props.accountId, true)
const { data: prices } = usePrices() const { data: prices } = usePrices()
const { data: vaultAprs } = useVaultAprs()
const { health, healthFactor } = useHealthComputer(account) const { health, healthFactor } = useHealthComputer(account)
const data = useBorrowMarketAssetsTableData() const data = useBorrowMarketAssetsTableData()
const borrowAssets = useMemo(() => data?.allAssets || [], [data]) const borrowAssets = useMemo(() => data?.allAssets || [], [data])
@ -37,6 +39,7 @@ function Content(props: Props) {
lendingAssets, lendingAssets,
hlsStrategies, hlsStrategies,
assets, assets,
vaultAprs,
account.kind === 'high_levered_strategy', account.kind === 'high_levered_strategy',
) )
@ -78,7 +81,7 @@ function Content(props: Props) {
sub: DEFAULT_PORTFOLIO_STATS[4].sub, sub: DEFAULT_PORTFOLIO_STATS[4].sub,
}, },
] ]
}, [account, assets, borrowAssets, hlsStrategies, lendingAssets, prices]) }, [account, assets, borrowAssets, hlsStrategies, lendingAssets, prices, vaultAprs])
return ( return (
<Skeleton <Skeleton

View File

@ -17,6 +17,7 @@ import useAccountId from 'hooks/useAccountId'
import useHealthComputer from 'hooks/useHealthComputer' import useHealthComputer from 'hooks/useHealthComputer'
import useHLSStakingAssets from 'hooks/useHLSStakingAssets' import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
import usePrices from 'hooks/usePrices' import usePrices from 'hooks/usePrices'
import useVaultAprs from 'hooks/vaults/useVaultAprs'
import { import {
calculateAccountApr, calculateAccountApr,
calculateAccountLeverage, calculateAccountLeverage,
@ -37,6 +38,7 @@ export default function PortfolioCard(props: Props) {
const { allAssets: lendingAssets } = useLendingMarketAssetsTableData() const { allAssets: lendingAssets } = useLendingMarketAssetsTableData()
const data = useBorrowMarketAssetsTableData() const data = useBorrowMarketAssetsTableData()
const { data: hlsStrategies } = useHLSStakingAssets() const { data: hlsStrategies } = useHLSStakingAssets()
const { data: vaultAprs } = useVaultAprs()
const [searchParams] = useSearchParams() const [searchParams] = useSearchParams()
const assets = useAllAssets() const assets = useAllAssets()
const borrowAssets = useMemo(() => data?.allAssets || [], [data]) const borrowAssets = useMemo(() => data?.allAssets || [], [data])
@ -64,9 +66,10 @@ export default function PortfolioCard(props: Props) {
prices, prices,
hlsStrategies, hlsStrategies,
assets, assets,
vaultAprs,
account.kind === 'high_levered_strategy', account.kind === 'high_levered_strategy',
) )
}, [lendingAssets, borrowAssets, prices, account, hlsStrategies, assets]) }, [lendingAssets, borrowAssets, prices, account, hlsStrategies, assets, vaultAprs])
const stats: { title: ReactNode; sub: string }[] = useMemo(() => { const stats: { title: ReactNode; sub: string }[] = useMemo(() => {
const isLoaded = account && prices.length && apr !== null const isLoaded = account && prices.length && apr !== null

View File

@ -11,6 +11,7 @@ import useAccounts from 'hooks/accounts/useAccounts'
import useAllAssets from 'hooks/assets/useAllAssets' import useAllAssets from 'hooks/assets/useAllAssets'
import useHLSStakingAssets from 'hooks/useHLSStakingAssets' import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
import usePrices from 'hooks/usePrices' import usePrices from 'hooks/usePrices'
import useVaultAprs from 'hooks/vaults/useVaultAprs'
import useStore from 'store' import useStore from 'store'
import { getAccountSummaryStats } from 'utils/accounts' import { getAccountSummaryStats } from 'utils/accounts'
import { DEFAULT_PORTFOLIO_STATS } from 'utils/constants' import { DEFAULT_PORTFOLIO_STATS } from 'utils/constants'
@ -24,6 +25,7 @@ export default function PortfolioSummary() {
const { allAssets: lendingAssets } = useLendingMarketAssetsTableData() const { allAssets: lendingAssets } = useLendingMarketAssetsTableData()
const { data: accounts } = useAccounts('default', urlAddress || walletAddress) const { data: accounts } = useAccounts('default', urlAddress || walletAddress)
const { data: hlsStrategies } = useHLSStakingAssets() const { data: hlsStrategies } = useHLSStakingAssets()
const { data: vaultAprs } = useVaultAprs()
const assets = useAllAssets() const assets = useAllAssets()
const stats = useMemo(() => { const stats = useMemo(() => {
if (!accounts?.length) return if (!accounts?.length) return
@ -53,6 +55,7 @@ export default function PortfolioSummary() {
lendingAssets, lendingAssets,
hlsStrategies, hlsStrategies,
assets, assets,
vaultAprs,
) )
return [ return [
@ -93,7 +96,7 @@ export default function PortfolioSummary() {
sub: 'Combined leverage', sub: 'Combined leverage',
}, },
] ]
}, [accounts, assets, borrowAssets, hlsStrategies, lendingAssets, prices]) }, [accounts, assets, borrowAssets, hlsStrategies, lendingAssets, prices, vaultAprs])
if (!walletAddress && !urlAddress) return null if (!walletAddress && !urlAddress) return null

View File

@ -0,0 +1,40 @@
import useSWR from 'swr'
import useChainConfig from 'hooks/useChainConfig'
import { convertAprToApy } from 'utils/parsers'
export default function useVaultAprs() {
const chainConfig = useChainConfig()
return useSWR(`chains/${chainConfig.id}/vaults/aprs`, () => getAprs(chainConfig), {
fallbackData: getEmptyAprData(chainConfig),
})
}
async function getAprs(chainConfig: ChainConfig) {
if (!chainConfig.farm) return []
try {
const response = await fetch(chainConfig.endpoints.aprs.vaults)
if (response.ok) {
const data: AprResponse = await response.json()
return data.vaults.map((aprData) => {
const finalApr = aprData.apr.projected_apr * 100
return {
address: aprData.address,
apr: finalApr,
apy: convertAprToApy(finalApr, 365),
} as Apr
})
}
return getEmptyAprData(chainConfig, null)
} catch {
return getEmptyAprData(chainConfig, null)
}
}
function getEmptyAprData(chainConfig: ChainConfig, apr?: null) {
return chainConfig.vaults.map((vault) => ({ address: vault.address, apr: apr, apy: apr }) as Apr)
}

View File

@ -20,7 +20,7 @@ interface AccountChange extends Account {
interface AccountBalanceRow { interface AccountBalanceRow {
amount: BigNumber amount: BigNumber
apy: number apy?: number | null
denom: string denom: string
size: number size: number
symbol: string symbol: string
@ -30,7 +30,7 @@ interface AccountBalanceRow {
} }
interface AccountStrategyRow { interface AccountStrategyRow {
apy: number apy?: number | null
name: string name: string
denom: string denom: string
amount: BNCoin[] amount: BNCoin[]

View File

@ -39,8 +39,8 @@ interface Vault extends VaultConfig {
maxLeverage: number maxLeverage: number
borrowDenom: string borrowDenom: string
} }
apy: number | null apr?: number | null
apr: number | null apy?: number | null
} }
interface VaultValuesAndAmounts { interface VaultValuesAndAmounts {
@ -120,5 +120,6 @@ interface AprBreakdown {
interface Apr { interface Apr {
address: string address: string
apr: number apr?: number | null
apy?: number | null
} }

View File

@ -72,6 +72,7 @@ export const calculateAccountApr = (
prices: BNCoin[], prices: BNCoin[],
hlsStrategies: HLSStrategy[], hlsStrategies: HLSStrategy[],
assets: Asset[], assets: Asset[],
vaultAprs: Apr[],
isHls?: boolean, isHls?: boolean,
): BigNumber => { ): BigNumber => {
const depositValue = calculateAccountValue('deposits', account, prices, assets) const depositValue = calculateAccountValue('deposits', account, prices, assets)
@ -125,8 +126,10 @@ export const calculateAccountApr = (
}) })
vaults?.forEach((vault) => { vaults?.forEach((vault) => {
const apr = vaultAprs.find((vaultApr) => vaultApr.address === vault.address)?.apr
if (!apr) return
const lockedValue = vault.values.primary.plus(vault.values.secondary) const lockedValue = vault.values.primary.plus(vault.values.secondary)
const positionInterest = lockedValue.multipliedBy(vault?.apr ?? 0).dividedBy(100) const positionInterest = lockedValue.multipliedBy(apr).dividedBy(100)
totalVaultsInterestValue = totalVaultsInterestValue.plus(positionInterest) totalVaultsInterestValue = totalVaultsInterestValue.plus(positionInterest)
}) })
@ -307,6 +310,7 @@ export function getAccountSummaryStats(
lendingAssets: LendingMarketTableData[], lendingAssets: LendingMarketTableData[],
hlsStrategies: HLSStrategy[], hlsStrategies: HLSStrategy[],
assets: Asset[], assets: Asset[],
vaultAprs: Apr[],
isHls?: boolean, isHls?: boolean,
) { ) {
const [deposits, lends, debts, vaults] = getAccountPositionValues(account, prices, assets) const [deposits, lends, debts, vaults] = getAccountPositionValues(account, prices, assets)
@ -318,6 +322,7 @@ export function getAccountSummaryStats(
prices, prices,
hlsStrategies, hlsStrategies,
assets, assets,
vaultAprs,
isHls, isHls,
) )
const leverage = calculateAccountLeverage(account, prices, assets) const leverage = calculateAccountLeverage(account, prices, assets)

View File

@ -5,7 +5,7 @@ export const debugSWR: Middleware = (useSWRNext: SWRHook) => (key, fetcher, conf
const startTime = Date.now() const startTime = Date.now()
const res = await fetcher!(...args) const res = await fetcher!(...args)
process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'production' &&
console.log('⬇️ GET: ', key, ' in ', Date.now() - startTime, 'ms') console.log('⬇️ GET: ', key, ' in ', Date.now() - startTime, 'ms', 'data: ', res)
return res return res
} }
// ... // ...