Deposit Cap and Utilization Fix (#654)
* fix: fixed the deposit cap and total supplied / utilization rate * fix: fixed build * fix: fixed build * fix: avoid deposit cap usage over 100% * refactor market data apy/ltv * fix: fixed the withdraw from vaults modal * tidy: refactor --------- Co-authored-by: Bob van der Helm <34470358+bobthebuidlr@users.noreply.github.com>
This commit is contained in:
parent
e7ce4f600a
commit
85533cdea3
@ -1,11 +1,11 @@
|
|||||||
import getMarket from 'api/markets/getMarket'
|
|
||||||
import getTotalActiveEmissionValue from 'api/incentives/getTotalActiveEmissionValue'
|
import getTotalActiveEmissionValue from 'api/incentives/getTotalActiveEmissionValue'
|
||||||
|
import getMarket from 'api/markets/getMarket'
|
||||||
import getUnderlyingLiquidityAmount from 'api/markets/getMarketUnderlyingLiquidityAmount'
|
import getUnderlyingLiquidityAmount from 'api/markets/getMarketUnderlyingLiquidityAmount'
|
||||||
import { BN } from 'utils/helpers'
|
|
||||||
import { SECONDS_IN_A_YEAR } from 'utils/constants'
|
|
||||||
import getPrice from 'api/prices/getPrice'
|
import getPrice from 'api/prices/getPrice'
|
||||||
import { ASSETS } from 'constants/assets'
|
import { ASSETS } from 'constants/assets'
|
||||||
import { byDenom } from 'utils/array'
|
import { byDenom } from 'utils/array'
|
||||||
|
import { SECONDS_IN_A_YEAR } from 'utils/constants'
|
||||||
|
import { BN } from 'utils/helpers'
|
||||||
|
|
||||||
export default async function calculateAssetIncentivesApy(
|
export default async function calculateAssetIncentivesApy(
|
||||||
denom: string,
|
denom: string,
|
||||||
@ -29,7 +29,7 @@ export default async function calculateAssetIncentivesApy(
|
|||||||
.shiftedBy(-assetDecimals)
|
.shiftedBy(-assetDecimals)
|
||||||
.multipliedBy(assetPrice)
|
.multipliedBy(assetPrice)
|
||||||
|
|
||||||
const marketReturns = BN(market.liquidityRate).multipliedBy(marketLiquidityValue)
|
const marketReturns = BN(market.apy.deposit).multipliedBy(marketLiquidityValue)
|
||||||
const annualEmission = totalActiveEmissionValue.multipliedBy(SECONDS_IN_A_YEAR)
|
const annualEmission = totalActiveEmissionValue.multipliedBy(SECONDS_IN_A_YEAR)
|
||||||
|
|
||||||
const totalAnnualReturnsValue = annualEmission.plus(marketReturns)
|
const totalAnnualReturnsValue = annualEmission.plus(marketReturns)
|
||||||
|
@ -17,7 +17,7 @@ export default async function getMarketBorrowings(): Promise<BorrowAsset[]> {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
...asset,
|
...asset,
|
||||||
borrowRate: market.borrowRate ?? 0,
|
borrowRate: market.apy.borrow ?? 0,
|
||||||
liquidity: {
|
liquidity: {
|
||||||
amount: BN(amount),
|
amount: BN(amount),
|
||||||
value: BN(amount).multipliedBy(price),
|
value: BN(amount).multipliedBy(price),
|
||||||
|
@ -8,8 +8,6 @@ import { ASSETS } from 'constants/assets'
|
|||||||
import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
|
import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
|
||||||
import usePrices from 'hooks/usePrices'
|
import usePrices from 'hooks/usePrices'
|
||||||
import { byDenom } from 'utils/array'
|
import { byDenom } from 'utils/array'
|
||||||
import { convertLiquidityRateToAPR } from 'utils/formatters'
|
|
||||||
import { convertAprToApy } from 'utils/parsers'
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
account: Account
|
account: Account
|
||||||
@ -45,11 +43,9 @@ export default function useAccountBalanceData(props: Props) {
|
|||||||
|
|
||||||
const lends = accountLends.map((lending) => {
|
const lends = accountLends.map((lending) => {
|
||||||
const asset = ASSETS.find(byDenom(lending.denom)) ?? ASSETS[0]
|
const asset = ASSETS.find(byDenom(lending.denom)) ?? ASSETS[0]
|
||||||
const apr = convertLiquidityRateToAPR(
|
const apy =
|
||||||
lendingData.find((market) => market.asset.denom === lending.denom)?.marketLiquidityRate ??
|
lendingData.find((market) => market.asset.denom === lending.denom)?.apy.deposit ?? 0
|
||||||
0,
|
|
||||||
)
|
|
||||||
const apy = convertAprToApy(apr, 365)
|
|
||||||
const prevLending = updatedAccount
|
const prevLending = updatedAccount
|
||||||
? account?.lends.find((position) => position.denom === lending.denom)
|
? account?.lends.find((position) => position.denom === lending.denom)
|
||||||
: lending
|
: lending
|
||||||
@ -66,7 +62,7 @@ export default function useAccountBalanceData(props: Props) {
|
|||||||
|
|
||||||
const debts = accountDebts.map((debt) => {
|
const debts = accountDebts.map((debt) => {
|
||||||
const asset = ASSETS.find(byDenom(debt.denom)) ?? ASSETS[0]
|
const asset = ASSETS.find(byDenom(debt.denom)) ?? ASSETS[0]
|
||||||
const apy = borrowingData.find((market) => market.asset.denom === debt.denom)?.borrowRate ?? 0
|
const apy = borrowingData.find((market) => market.asset.denom === debt.denom)?.apy.borrow ?? 0
|
||||||
const prevDebt = updatedAccount
|
const prevDebt = updatedAccount
|
||||||
? account?.debts.find((position) => position.denom === debt.denom)
|
? account?.debts.find((position) => position.denom === debt.denom)
|
||||||
: debt
|
: debt
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
import React from 'react'
|
|
||||||
|
|
||||||
import AvailableBorrowingsTable from 'components/Borrow/Table/AvailableBorrowingsTable'
|
import AvailableBorrowingsTable from 'components/Borrow/Table/AvailableBorrowingsTable'
|
||||||
import DepositedBorrowingsTable from 'components/Borrow/Table/DepositedBorrowingsTable'
|
import DepositedBorrowingsTable from 'components/Borrow/Table/DepositedBorrowingsTable'
|
||||||
import { BN_ZERO } from 'constants/math'
|
import { BN_ZERO } from 'constants/math'
|
||||||
@ -24,13 +22,18 @@ function Fallback() {
|
|||||||
const assets = getBorrowEnabledAssets()
|
const assets = getBorrowEnabledAssets()
|
||||||
const data: BorrowMarketTableData[] = assets.map((asset) => ({
|
const data: BorrowMarketTableData[] = assets.map((asset) => ({
|
||||||
asset,
|
asset,
|
||||||
borrowRate: null,
|
apy: {
|
||||||
|
borrow: 0,
|
||||||
|
deposit: 0,
|
||||||
|
},
|
||||||
|
ltv: {
|
||||||
|
max: 0,
|
||||||
|
liq: 0,
|
||||||
|
},
|
||||||
liquidity: null,
|
liquidity: null,
|
||||||
marketMaxLtv: 0,
|
|
||||||
marketDepositAmount: BN_ZERO,
|
marketDepositAmount: BN_ZERO,
|
||||||
marketLiquidityRate: 0,
|
marketLiquidityRate: 0,
|
||||||
marketLiquidityAmount: BN_ZERO,
|
marketLiquidityAmount: BN_ZERO,
|
||||||
marketLiquidationThreshold: 0,
|
|
||||||
}))
|
}))
|
||||||
|
|
||||||
return <AvailableBorrowingsTable data={data} isLoading />
|
return <AvailableBorrowingsTable data={data} isLoading />
|
||||||
|
@ -18,7 +18,7 @@ export default function useAvailableColumns() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
...BORROW_RATE_META,
|
...BORROW_RATE_META,
|
||||||
cell: ({ row }) => <BorrowRate borrowRate={row.original.borrowRate} />,
|
cell: ({ row }) => <BorrowRate borrowRate={row.original.apy.borrow} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
...LIQUIDITY_META,
|
...LIQUIDITY_META,
|
||||||
|
@ -24,7 +24,7 @@ export default function useDepositedColumns() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
...BORROW_RATE_META,
|
...BORROW_RATE_META,
|
||||||
cell: ({ row }) => <BorrowRate borrowRate={row.original.borrowRate} />,
|
cell: ({ row }) => <BorrowRate borrowRate={row.original.apy.borrow} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
...LIQUIDITY_META,
|
...LIQUIDITY_META,
|
||||||
|
@ -12,7 +12,7 @@ export default function DepositCapCell(props: Props) {
|
|||||||
.dividedBy(props.depositCap.max.multipliedBy(VAULT_DEPOSIT_BUFFER))
|
.dividedBy(props.depositCap.max.multipliedBy(VAULT_DEPOSIT_BUFFER))
|
||||||
.multipliedBy(100)
|
.multipliedBy(100)
|
||||||
.integerValue()
|
.integerValue()
|
||||||
|
const depositCapUsed = Math.min(percent.toNumber(), 100)
|
||||||
const decimals = getAssetByDenom(props.depositCap.denom)?.decimals ?? 6
|
const decimals = getAssetByDenom(props.depositCap.denom)?.decimals ?? 6
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -27,7 +27,7 @@ export default function DepositCapCell(props: Props) {
|
|||||||
}
|
}
|
||||||
sub={
|
sub={
|
||||||
<FormattedNumber
|
<FormattedNumber
|
||||||
amount={percent.toNumber()}
|
amount={depositCapUsed}
|
||||||
options={{ minDecimals: 2, maxDecimals: 2, suffix: '% Filled' }}
|
options={{ minDecimals: 2, maxDecimals: 2, suffix: '% Filled' }}
|
||||||
className='text-xs'
|
className='text-xs'
|
||||||
animate
|
animate
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
import React from 'react'
|
|
||||||
|
|
||||||
import AvailableLendsTable from 'components/Earn/Lend/Table/AvailableLendsTable'
|
import AvailableLendsTable from 'components/Earn/Lend/Table/AvailableLendsTable'
|
||||||
import DepositedLendsTable from 'components/Earn/Lend/Table/DepositedLendsTable'
|
import DepositedLendsTable from 'components/Earn/Lend/Table/DepositedLendsTable'
|
||||||
import { BN_ZERO } from 'constants/math'
|
import { BN_ZERO } from 'constants/math'
|
||||||
@ -26,11 +24,21 @@ function Fallback() {
|
|||||||
asset,
|
asset,
|
||||||
marketDepositCap: BN_ZERO,
|
marketDepositCap: BN_ZERO,
|
||||||
borrowEnabled: false,
|
borrowEnabled: false,
|
||||||
marketMaxLtv: 0,
|
|
||||||
marketDepositAmount: BN_ZERO,
|
marketDepositAmount: BN_ZERO,
|
||||||
marketLiquidityRate: 0,
|
|
||||||
marketLiquidityAmount: BN_ZERO,
|
marketLiquidityAmount: BN_ZERO,
|
||||||
marketLiquidationThreshold: 0,
|
cap: {
|
||||||
|
max: BN_ZERO,
|
||||||
|
used: BN_ZERO,
|
||||||
|
denom: asset.denom,
|
||||||
|
},
|
||||||
|
apy: {
|
||||||
|
borrow: 0,
|
||||||
|
deposit: 0,
|
||||||
|
},
|
||||||
|
ltv: {
|
||||||
|
max: 0,
|
||||||
|
liq: 0,
|
||||||
|
},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
return <AvailableLendsTable data={data} isLoading />
|
return <AvailableLendsTable data={data} isLoading />
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import AssetRate from 'components/Asset/AssetRate'
|
import AssetRate from 'components/Asset/AssetRate'
|
||||||
import Loading from 'components/Loading'
|
import Loading from 'components/Loading'
|
||||||
import { convertAprToApy } from 'utils/parsers'
|
|
||||||
|
|
||||||
export const APY_META = { accessorKey: 'marketLiquidityRate', header: 'APY' }
|
export const APY_META = { accessorKey: 'apy.deposit', header: 'APY' }
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
marketLiquidityRate: number
|
apy: number
|
||||||
borrowEnabled: boolean
|
borrowEnabled: boolean
|
||||||
isLoading: boolean
|
isLoading: boolean
|
||||||
}
|
}
|
||||||
@ -14,7 +13,7 @@ export default function Apr(props: Props) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<AssetRate
|
<AssetRate
|
||||||
rate={convertAprToApy(props.marketLiquidityRate ?? 0, 365)}
|
rate={props.apy ?? 0}
|
||||||
isEnabled={props.borrowEnabled}
|
isEnabled={props.borrowEnabled}
|
||||||
className='justify-end text-xs'
|
className='justify-end text-xs'
|
||||||
type='apy'
|
type='apy'
|
||||||
|
@ -17,10 +17,10 @@ export const marketDepositCapSortingFn = (
|
|||||||
): number => {
|
): number => {
|
||||||
const assetA = a.original.asset
|
const assetA = a.original.asset
|
||||||
const assetB = b.original.asset
|
const assetB = b.original.asset
|
||||||
if (!a.original.marketDepositCap || !b.original.marketDepositCap) return 0
|
if (!a.original.cap.max || !b.original.cap.max) return 0
|
||||||
|
|
||||||
const marketDepositCapA = demagnify(a.original.marketDepositCap, assetA)
|
const marketDepositCapA = demagnify(a.original.cap.max, assetA)
|
||||||
const marketDepositCapB = demagnify(b.original.marketDepositCap, assetB)
|
const marketDepositCapB = demagnify(b.original.cap.max, assetB)
|
||||||
return marketDepositCapA - marketDepositCapB
|
return marketDepositCapA - marketDepositCapB
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,22 +30,23 @@ interface Props {
|
|||||||
}
|
}
|
||||||
export default function DepositCap(props: Props) {
|
export default function DepositCap(props: Props) {
|
||||||
if (props.isLoading) return <Loading />
|
if (props.isLoading) return <Loading />
|
||||||
const { marketDepositCap, marketDepositAmount, asset } = props.data
|
const { cap, asset } = props.data
|
||||||
const percent = marketDepositAmount.dividedBy(marketDepositCap).multipliedBy(100)
|
const percent = cap.used.dividedBy(cap.max).multipliedBy(100)
|
||||||
|
const depositCapUsed = Math.min(percent.toNumber(), 100)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TitleAndSubCell
|
<TitleAndSubCell
|
||||||
className='text-xs'
|
className='text-xs'
|
||||||
title={
|
title={
|
||||||
<FormattedNumber
|
<FormattedNumber
|
||||||
amount={marketDepositCap.toNumber()}
|
amount={cap.max.toNumber()}
|
||||||
options={{ abbreviated: true, decimals: asset.decimals }}
|
options={{ abbreviated: true, decimals: asset.decimals }}
|
||||||
animate
|
animate
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
sub={
|
sub={
|
||||||
<FormattedNumber
|
<FormattedNumber
|
||||||
amount={percent.toNumber()}
|
amount={depositCapUsed}
|
||||||
options={{ minDecimals: 2, maxDecimals: 2, suffix: '% used' }}
|
options={{ minDecimals: 2, maxDecimals: 2, suffix: '% used' }}
|
||||||
animate
|
animate
|
||||||
/>
|
/>
|
||||||
|
@ -26,7 +26,7 @@ export default function useAvailableColumns(props: Props) {
|
|||||||
<Apy
|
<Apy
|
||||||
isLoading={props.isLoading}
|
isLoading={props.isLoading}
|
||||||
borrowEnabled={row.original.borrowEnabled}
|
borrowEnabled={row.original.borrowEnabled}
|
||||||
marketLiquidityRate={row.original.marketLiquidityRate}
|
apy={row.original.apy.deposit}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
@ -37,7 +37,7 @@ export default function useDepositedColumns(props: Props) {
|
|||||||
<Apy
|
<Apy
|
||||||
isLoading={props.isLoading}
|
isLoading={props.isLoading}
|
||||||
borrowEnabled={row.original.borrowEnabled}
|
borrowEnabled={row.original.borrowEnabled}
|
||||||
marketLiquidityRate={row.original.marketLiquidityRate}
|
apy={row.original.apy.deposit}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
@ -23,13 +23,7 @@ export default function MarketDetails({ row, type }: Props) {
|
|||||||
symbol: displayCurrencySymbol,
|
symbol: displayCurrencySymbol,
|
||||||
} = useDisplayCurrencyPrice()
|
} = useDisplayCurrencyPrice()
|
||||||
|
|
||||||
const {
|
const { asset, ltv, marketDepositAmount, marketLiquidityAmount } = row.original
|
||||||
asset,
|
|
||||||
marketMaxLtv,
|
|
||||||
marketDepositAmount,
|
|
||||||
marketLiquidityAmount,
|
|
||||||
marketLiquidationThreshold,
|
|
||||||
} = row.original
|
|
||||||
|
|
||||||
const totalBorrowed = marketDepositAmount.minus(marketLiquidityAmount)
|
const totalBorrowed = marketDepositAmount.minus(marketLiquidityAmount)
|
||||||
|
|
||||||
@ -48,12 +42,12 @@ export default function MarketDetails({ row, type }: Props) {
|
|||||||
title: 'Total Supplied',
|
title: 'Total Supplied',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
amount: marketMaxLtv * 100,
|
amount: ltv.max * 100,
|
||||||
options: { minDecimals: 2, maxDecimals: 2, suffix: '%' },
|
options: { minDecimals: 2, maxDecimals: 2, suffix: '%' },
|
||||||
title: 'Max LTV',
|
title: 'Max LTV',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
amount: marketLiquidationThreshold * 100,
|
amount: ltv.liq * 100,
|
||||||
options: { minDecimals: 2, maxDecimals: 2, suffix: '%' },
|
options: { minDecimals: 2, maxDecimals: 2, suffix: '%' },
|
||||||
title: 'Liquidation LTV',
|
title: 'Liquidation LTV',
|
||||||
},
|
},
|
||||||
@ -114,8 +108,7 @@ export default function MarketDetails({ row, type }: Props) {
|
|||||||
type,
|
type,
|
||||||
asset,
|
asset,
|
||||||
marketDepositAmount,
|
marketDepositAmount,
|
||||||
marketMaxLtv,
|
ltv,
|
||||||
marketLiquidationThreshold,
|
|
||||||
totalBorrowed,
|
totalBorrowed,
|
||||||
displayCurrencySymbol,
|
displayCurrencySymbol,
|
||||||
convertAmount,
|
convertAmount,
|
||||||
|
@ -10,7 +10,6 @@ import Text from 'components/Text'
|
|||||||
import { BNCoin } from 'types/classes/BNCoin'
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
import { getAssetByDenom } from 'utils/assets'
|
import { getAssetByDenom } from 'utils/assets'
|
||||||
import { demagnify, formatPercent } from 'utils/formatters'
|
import { demagnify, formatPercent } from 'utils/formatters'
|
||||||
import { convertAprToApy } from 'utils/parsers'
|
|
||||||
|
|
||||||
function showBorrowRate(data: AssetTableRow[]) {
|
function showBorrowRate(data: AssetTableRow[]) {
|
||||||
const assetData = data.length && (data[0].asset as BorrowAsset)
|
const assetData = data.length && (data[0].asset as BorrowAsset)
|
||||||
@ -29,8 +28,7 @@ export default function useAssetTableColumns(isBorrow: boolean) {
|
|||||||
const market = row.original.market
|
const market = row.original.market
|
||||||
const borrowAsset = row.original.asset as BorrowAsset
|
const borrowAsset = row.original.asset as BorrowAsset
|
||||||
const showRate = !borrowAsset?.borrowRate
|
const showRate = !borrowAsset?.borrowRate
|
||||||
const rate = isBorrow ? market?.borrowRate : market?.liquidityRate
|
const apy = isBorrow ? market?.apy.borrow : market?.apy.deposit
|
||||||
const apy = convertAprToApy(rate ?? 0, 365)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex items-center'>
|
<div className='flex items-center'>
|
||||||
@ -47,7 +45,7 @@ export default function useAssetTableColumns(isBorrow: boolean) {
|
|||||||
</Text>
|
</Text>
|
||||||
{showRate && market ? (
|
{showRate && market ? (
|
||||||
<AssetRate
|
<AssetRate
|
||||||
rate={apy}
|
rate={apy ?? 0}
|
||||||
isEnabled={market.borrowEnabled}
|
isEnabled={market.borrowEnabled}
|
||||||
className='text-xs'
|
className='text-xs'
|
||||||
type='apy'
|
type='apy'
|
||||||
|
@ -81,7 +81,7 @@ function BorrowModal(props: Props) {
|
|||||||
const [max, setMax] = useState(BN_ZERO)
|
const [max, setMax] = useState(BN_ZERO)
|
||||||
const { simulateBorrow, simulateRepay } = useUpdatedAccount(account)
|
const { simulateBorrow, simulateRepay } = useUpdatedAccount(account)
|
||||||
const { autoLendEnabledAccountIds } = useAutoLend()
|
const { autoLendEnabledAccountIds } = useAutoLend()
|
||||||
const apr = modal.marketData?.borrowRate ?? '0'
|
const apy = modal.marketData.apy.borrow
|
||||||
const isAutoLendEnabled = autoLendEnabledAccountIds.includes(account.id)
|
const isAutoLendEnabled = autoLendEnabledAccountIds.includes(account.id)
|
||||||
const { computeMaxBorrowAmount } = useHealthComputer(account)
|
const { computeMaxBorrowAmount } = useHealthComputer(account)
|
||||||
const totalDebt = BN(getDebtAmount(modal))
|
const totalDebt = BN(getDebtAmount(modal))
|
||||||
@ -95,8 +95,8 @@ function BorrowModal(props: Props) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
const totalDebtRepayAmount = useMemo(
|
const totalDebtRepayAmount = useMemo(
|
||||||
() => getDebtAmountWithInterest(totalDebt, Number(apr)),
|
() => getDebtAmountWithInterest(totalDebt, apy),
|
||||||
[totalDebt, apr],
|
[totalDebt, apy],
|
||||||
)
|
)
|
||||||
|
|
||||||
const maxRepayAmount = useMemo(() => {
|
const maxRepayAmount = useMemo(() => {
|
||||||
@ -201,7 +201,7 @@ function BorrowModal(props: Props) {
|
|||||||
>
|
>
|
||||||
<div className='flex gap-3 px-6 py-4 border-b border-white/5 gradient-header'>
|
<div className='flex gap-3 px-6 py-4 border-b border-white/5 gradient-header'>
|
||||||
<TitleAndSubCell
|
<TitleAndSubCell
|
||||||
title={formatPercent(modal.marketData.borrowRate || '0')}
|
title={formatPercent(modal.marketData.apy.borrow)}
|
||||||
sub={'Borrow Rate APY'}
|
sub={'Borrow Rate APY'}
|
||||||
/>
|
/>
|
||||||
{totalDebt.isGreaterThan(0) && (
|
{totalDebt.isGreaterThan(0) && (
|
||||||
|
@ -10,7 +10,7 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function DetailsHeader({ data }: Props) {
|
function DetailsHeader({ data }: Props) {
|
||||||
const { asset, marketDepositCap, accountLentAmount } = data
|
const { asset, cap, accountLentAmount } = data
|
||||||
const { data: assetApy } = useAssetIncentivesApy(asset.denom)
|
const { data: assetApy } = useAssetIncentivesApy(asset.denom)
|
||||||
const balanceInWallet = useCurrentWalletBalance(asset.denom)
|
const balanceInWallet = useCurrentWalletBalance(asset.denom)
|
||||||
|
|
||||||
@ -59,9 +59,7 @@ function DetailsHeader({ data }: Props) {
|
|||||||
)}
|
)}
|
||||||
<TitleAndSubCell
|
<TitleAndSubCell
|
||||||
title={
|
title={
|
||||||
<DisplayCurrency
|
<DisplayCurrency coin={new BNCoin({ denom: asset.denom, amount: cap.max.toString() })} />
|
||||||
coin={new BNCoin({ denom: asset.denom, amount: marketDepositCap.toString() })}
|
|
||||||
/>
|
|
||||||
}
|
}
|
||||||
sub={'Deposit Cap'}
|
sub={'Deposit Cap'}
|
||||||
/>
|
/>
|
||||||
|
@ -225,7 +225,7 @@ export default function VaultBorrowings(props: VaultBorrowingsProps) {
|
|||||||
</div>
|
</div>
|
||||||
{props.borrowings.map((coin) => {
|
{props.borrowings.map((coin) => {
|
||||||
const asset = getAssetByDenom(coin.denom)
|
const asset = getAssetByDenom(coin.denom)
|
||||||
const borrowRate = marketAssets?.find((market) => market.denom === coin.denom)?.borrowRate
|
const borrowRate = marketAssets?.find((market) => market.denom === coin.denom)?.apy.borrow
|
||||||
|
|
||||||
if (!asset || !borrowRate)
|
if (!asset || !borrowRate)
|
||||||
return <React.Fragment key={`borrow-rate-${coin.denom}`}></React.Fragment>
|
return <React.Fragment key={`borrow-rate-${coin.denom}`}></React.Fragment>
|
||||||
|
@ -7,18 +7,20 @@ import Modal from 'components/Modal'
|
|||||||
import Text from 'components/Text'
|
import Text from 'components/Text'
|
||||||
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
||||||
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
||||||
|
import { ORACLE_DENOM } from 'constants/oracle'
|
||||||
import useAccountId from 'hooks/useAccountId'
|
import useAccountId from 'hooks/useAccountId'
|
||||||
import useLocalStorage from 'hooks/useLocalStorage'
|
import useLocalStorage from 'hooks/useLocalStorage'
|
||||||
|
import usePrices from 'hooks/usePrices'
|
||||||
import useStore from 'store'
|
import useStore from 'store'
|
||||||
import { BNCoin } from 'types/classes/BNCoin'
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
|
import { byDenom } from 'utils/array'
|
||||||
import { getAssetByDenom } from 'utils/assets'
|
import { getAssetByDenom } from 'utils/assets'
|
||||||
import { demagnify } from 'utils/formatters'
|
|
||||||
|
|
||||||
export default function WithdrawFromVaultsModal() {
|
export default function WithdrawFromVaultsModal() {
|
||||||
const modal = useStore((s) => s.withdrawFromVaultsModal)
|
const modal = useStore((s) => s.withdrawFromVaultsModal)
|
||||||
const accountId = useAccountId()
|
const accountId = useAccountId()
|
||||||
|
const { data: prices } = usePrices()
|
||||||
const withdrawFromVaults = useStore((s) => s.withdrawFromVaults)
|
const withdrawFromVaults = useStore((s) => s.withdrawFromVaults)
|
||||||
const baseCurrency = useStore((s) => s.baseCurrency)
|
|
||||||
const [slippage] = useLocalStorage<number>(LocalStorageKeys.SLIPPAGE, DEFAULT_SETTINGS.slippage)
|
const [slippage] = useLocalStorage<number>(LocalStorageKeys.SLIPPAGE, DEFAULT_SETTINGS.slippage)
|
||||||
|
|
||||||
function onClose() {
|
function onClose() {
|
||||||
@ -52,12 +54,18 @@ export default function WithdrawFromVaultsModal() {
|
|||||||
{modal ? (
|
{modal ? (
|
||||||
<div className='flex flex-wrap w-full gap-4'>
|
<div className='flex flex-wrap w-full gap-4'>
|
||||||
{modal.map((vault) => {
|
{modal.map((vault) => {
|
||||||
const positionValue = vault.values.primary.plus(vault.values.secondary)
|
const positionValue = vault.values.unlocking
|
||||||
const coin = BNCoin.fromDenomAndBigNumber(baseCurrency.denom, positionValue)
|
const coin = BNCoin.fromDenomAndBigNumber(ORACLE_DENOM, positionValue)
|
||||||
const primaryAsset = getAssetByDenom(vault.denoms.primary)
|
const primaryAsset = getAssetByDenom(vault.denoms.primary)
|
||||||
const secondaryAsset = getAssetByDenom(vault.denoms.secondary)
|
const secondaryAsset = getAssetByDenom(vault.denoms.secondary)
|
||||||
|
|
||||||
if (!primaryAsset || !secondaryAsset) return null
|
if (!primaryAsset || !secondaryAsset) return null
|
||||||
|
const primaryAssetPrice = prices.find(byDenom(primaryAsset.denom))?.amount ?? 1
|
||||||
|
const secondaryAssetPrice = prices.find(byDenom(secondaryAsset.denom))?.amount ?? 1
|
||||||
|
|
||||||
|
const primaryAssetAmount = positionValue.dividedBy(primaryAssetPrice).dividedBy(2)
|
||||||
|
const secondaryAssetAmount = positionValue.dividedBy(secondaryAssetPrice).dividedBy(2)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex items-center gap-4' key={vault.unlockId}>
|
<div className='flex items-center gap-4' key={vault.unlockId}>
|
||||||
<DoubleLogo
|
<DoubleLogo
|
||||||
@ -73,15 +81,21 @@ export default function WithdrawFromVaultsModal() {
|
|||||||
<div className='flex flex-wrap'>
|
<div className='flex flex-wrap'>
|
||||||
<DisplayCurrency coin={coin} className='w-full text-right' />
|
<DisplayCurrency coin={coin} className='w-full text-right' />
|
||||||
<FormattedNumber
|
<FormattedNumber
|
||||||
amount={demagnify(vault.amounts.primary, primaryAsset)}
|
amount={Number(primaryAssetAmount.toPrecision(4))}
|
||||||
className='w-full text-sm text-right text-white/50'
|
className='w-full text-sm text-right text-white/50'
|
||||||
options={{ suffix: ` ${vault.symbols.primary}` }}
|
options={{
|
||||||
|
suffix: ` ${vault.symbols.primary}`,
|
||||||
|
maxDecimals: primaryAsset.decimals,
|
||||||
|
}}
|
||||||
animate
|
animate
|
||||||
/>
|
/>
|
||||||
<FormattedNumber
|
<FormattedNumber
|
||||||
amount={demagnify(vault.amounts.secondary, secondaryAsset)}
|
amount={Number(secondaryAssetAmount.toPrecision(4))}
|
||||||
className='w-full text-sm text-right text-white/50'
|
className='w-full text-sm text-right text-white/50'
|
||||||
options={{ suffix: ` ${vault.symbols.secondary}` }}
|
options={{
|
||||||
|
suffix: ` ${vault.symbols.secondary}`,
|
||||||
|
maxDecimals: secondaryAsset.decimals,
|
||||||
|
}}
|
||||||
animate
|
animate
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -11,7 +11,6 @@ import useMarketAssets from 'hooks/useMarketAssets'
|
|||||||
import { BNCoin } from 'types/classes/BNCoin'
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
import { byDenom } from 'utils/array'
|
import { byDenom } from 'utils/array'
|
||||||
import { formatValue } from 'utils/formatters'
|
import { formatValue } from 'utils/formatters'
|
||||||
import { convertAprToApy } from 'utils/parsers'
|
|
||||||
|
|
||||||
interface Props extends SelectOption {
|
interface Props extends SelectOption {
|
||||||
isSelected?: boolean
|
isSelected?: boolean
|
||||||
@ -80,7 +79,7 @@ export default function Option(props: Props) {
|
|||||||
})}
|
})}
|
||||||
</Text>
|
</Text>
|
||||||
<AssetRate
|
<AssetRate
|
||||||
rate={convertAprToApy(marketAsset?.borrowRate ?? 0, 365)}
|
rate={marketAsset?.apy.borrow ?? 0}
|
||||||
isEnabled={marketAsset?.borrowEnabled ?? false}
|
isEnabled={marketAsset?.borrowEnabled ?? false}
|
||||||
className='col-span-2 text-white/50'
|
className='col-span-2 text-white/50'
|
||||||
type='apy'
|
type='apy'
|
||||||
|
@ -26,7 +26,7 @@ export default function useBorrowMarketAssetsTableData(suspense = true) {
|
|||||||
const accountBorrowedAssets: BorrowMarketTableData[] = [],
|
const accountBorrowedAssets: BorrowMarketTableData[] = [],
|
||||||
availableAssets: BorrowMarketTableData[] = []
|
availableAssets: BorrowMarketTableData[] = []
|
||||||
|
|
||||||
markets.forEach(({ denom, liquidityRate, liquidationThreshold, maxLtv }) => {
|
markets.forEach(({ denom, apy, ltv }) => {
|
||||||
const asset = getAssetByDenom(denom) as Asset
|
const asset = getAssetByDenom(denom) as Asset
|
||||||
const borrow = borrowData.find((borrow) => borrow.denom === denom)
|
const borrow = borrowData.find((borrow) => borrow.denom === denom)
|
||||||
const marketDepositAmount = BN(marketDeposits.find(byDenom(denom))?.amount ?? 0)
|
const marketDepositAmount = BN(marketDeposits.find(byDenom(denom))?.amount ?? 0)
|
||||||
@ -41,9 +41,8 @@ export default function useBorrowMarketAssetsTableData(suspense = true) {
|
|||||||
debt: debt?.amount,
|
debt: debt?.amount,
|
||||||
marketDepositAmount,
|
marketDepositAmount,
|
||||||
marketLiquidityAmount,
|
marketLiquidityAmount,
|
||||||
marketLiquidityRate: liquidityRate,
|
apy,
|
||||||
marketLiquidationThreshold: liquidationThreshold,
|
ltv,
|
||||||
marketMaxLtv: maxLtv,
|
|
||||||
}
|
}
|
||||||
;(borrowMarketAsset.debt ? accountBorrowedAssets : availableAssets).push(borrowMarketAsset)
|
;(borrowMarketAsset.debt ? accountBorrowedAssets : availableAssets).push(borrowMarketAsset)
|
||||||
})
|
})
|
||||||
|
@ -3,6 +3,7 @@ import { useMemo } from 'react'
|
|||||||
import useCurrentAccountLends from 'hooks/useCurrentAccountLends'
|
import useCurrentAccountLends from 'hooks/useCurrentAccountLends'
|
||||||
import useDepositEnabledMarkets from 'hooks/useDepositEnabledMarkets'
|
import useDepositEnabledMarkets from 'hooks/useDepositEnabledMarkets'
|
||||||
import useDisplayCurrencyPrice from 'hooks/useDisplayCurrencyPrice'
|
import useDisplayCurrencyPrice from 'hooks/useDisplayCurrencyPrice'
|
||||||
|
import useMarketDeposits from 'hooks/useMarketDeposits'
|
||||||
import useMarketLiquidities from 'hooks/useMarketLiquidities'
|
import useMarketLiquidities from 'hooks/useMarketLiquidities'
|
||||||
import { byDenom } from 'utils/array'
|
import { byDenom } from 'utils/array'
|
||||||
import { getAssetByDenom } from 'utils/assets'
|
import { getAssetByDenom } from 'utils/assets'
|
||||||
@ -16,46 +17,45 @@ function useLendingMarketAssetsTableData(): {
|
|||||||
const markets = useDepositEnabledMarkets()
|
const markets = useDepositEnabledMarkets()
|
||||||
const accountLentAmounts = useCurrentAccountLends()
|
const accountLentAmounts = useCurrentAccountLends()
|
||||||
const { data: marketLiquidities } = useMarketLiquidities()
|
const { data: marketLiquidities } = useMarketLiquidities()
|
||||||
|
const { data: marketDeposits } = useMarketDeposits()
|
||||||
const { convertAmount } = useDisplayCurrencyPrice()
|
const { convertAmount } = useDisplayCurrencyPrice()
|
||||||
|
|
||||||
return useMemo(() => {
|
return useMemo(() => {
|
||||||
const accountLentAssets: LendingMarketTableData[] = [],
|
const accountLentAssets: LendingMarketTableData[] = [],
|
||||||
availableAssets: LendingMarketTableData[] = []
|
availableAssets: LendingMarketTableData[] = []
|
||||||
|
|
||||||
markets.forEach(
|
markets.forEach(({ denom, cap, ltv, apy, borrowEnabled }) => {
|
||||||
({ denom, cap, liquidityRate, liquidationThreshold, maxLtv, borrowEnabled }) => {
|
const asset = getAssetByDenom(denom) as Asset
|
||||||
const asset = getAssetByDenom(denom) as Asset
|
const marketDepositAmount = BN(marketDeposits.find(byDenom(denom))?.amount ?? 0)
|
||||||
const marketLiquidityAmount = BN(marketLiquidities.find(byDenom(denom))?.amount ?? 0)
|
const marketLiquidityAmount = BN(marketLiquidities.find(byDenom(denom))?.amount ?? 0)
|
||||||
const accountLentAmount = accountLentAmounts.find(byDenom(denom))?.amount
|
const accountLentAmount = accountLentAmounts.find(byDenom(denom))?.amount
|
||||||
const accountLentValue = accountLentAmount
|
const accountLentValue = accountLentAmount
|
||||||
? convertAmount(asset, accountLentAmount)
|
? convertAmount(asset, accountLentAmount)
|
||||||
: undefined
|
: undefined
|
||||||
|
|
||||||
const lendingMarketAsset: LendingMarketTableData = {
|
const lendingMarketAsset: LendingMarketTableData = {
|
||||||
asset,
|
asset,
|
||||||
marketDepositAmount: cap.used,
|
marketDepositAmount,
|
||||||
accountLentValue,
|
accountLentValue,
|
||||||
accountLentAmount,
|
accountLentAmount,
|
||||||
marketLiquidityAmount,
|
marketLiquidityAmount,
|
||||||
marketDepositCap: cap.max,
|
apy,
|
||||||
marketLiquidityRate: liquidityRate,
|
ltv,
|
||||||
marketLiquidationThreshold: liquidationThreshold,
|
borrowEnabled,
|
||||||
marketMaxLtv: maxLtv,
|
cap,
|
||||||
borrowEnabled,
|
}
|
||||||
}
|
|
||||||
|
|
||||||
;(lendingMarketAsset.accountLentValue ? accountLentAssets : availableAssets).push(
|
;(lendingMarketAsset.accountLentValue ? accountLentAssets : availableAssets).push(
|
||||||
lendingMarketAsset,
|
lendingMarketAsset,
|
||||||
)
|
)
|
||||||
},
|
})
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
accountLentAssets,
|
accountLentAssets,
|
||||||
availableAssets,
|
availableAssets,
|
||||||
allAssets: [...accountLentAssets, ...availableAssets],
|
allAssets: [...accountLentAssets, ...availableAssets],
|
||||||
}
|
}
|
||||||
}, [markets, marketLiquidities, accountLentAmounts, convertAmount])
|
}, [markets, marketLiquidities, accountLentAmounts, marketDeposits, convertAmount])
|
||||||
}
|
}
|
||||||
|
|
||||||
export default useLendingMarketAssetsTableData
|
export default useLendingMarketAssetsTableData
|
||||||
|
14
src/types/interfaces/asset.d.ts
vendored
14
src/types/interfaces/asset.d.ts
vendored
@ -88,7 +88,6 @@ interface BigNumberCoin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface BorrowMarketTableData extends MarketTableData {
|
interface BorrowMarketTableData extends MarketTableData {
|
||||||
borrowRate: number | null
|
|
||||||
liquidity: {
|
liquidity: {
|
||||||
amount: BigNumber
|
amount: BigNumber
|
||||||
value: BigNumber
|
value: BigNumber
|
||||||
@ -97,19 +96,24 @@ interface BorrowMarketTableData extends MarketTableData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface LendingMarketTableData extends MarketTableData {
|
interface LendingMarketTableData extends MarketTableData {
|
||||||
marketDepositCap: BigNumber
|
|
||||||
accountLentAmount?: string
|
accountLentAmount?: string
|
||||||
accountLentValue?: BigNumber
|
accountLentValue?: BigNumber
|
||||||
borrowEnabled: boolean
|
borrowEnabled: boolean
|
||||||
|
cap: DepositCap
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MarketTableData {
|
interface MarketTableData {
|
||||||
asset: Asset
|
asset: Asset
|
||||||
marketMaxLtv: number
|
|
||||||
marketDepositAmount: BigNumber
|
marketDepositAmount: BigNumber
|
||||||
marketLiquidityRate: number
|
|
||||||
marketLiquidityAmount: BigNumber
|
marketLiquidityAmount: BigNumber
|
||||||
marketLiquidationThreshold: number
|
apy: {
|
||||||
|
borrow: number
|
||||||
|
deposit: number
|
||||||
|
}
|
||||||
|
ltv: {
|
||||||
|
max: number
|
||||||
|
liq: number
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface HLSStrategy extends HLSStrategyNoCap {
|
interface HLSStrategy extends HLSStrategyNoCap {
|
||||||
|
12
src/types/interfaces/market.d.ts
vendored
12
src/types/interfaces/market.d.ts
vendored
@ -1,12 +1,16 @@
|
|||||||
interface Market {
|
interface Market {
|
||||||
denom: string
|
denom: string
|
||||||
borrowRate: number
|
|
||||||
debtTotalScaled: string
|
debtTotalScaled: string
|
||||||
collateralTotalScaled: string
|
collateralTotalScaled: string
|
||||||
depositEnabled: boolean
|
depositEnabled: boolean
|
||||||
borrowEnabled: boolean
|
borrowEnabled: boolean
|
||||||
cap: DepositCap
|
cap: DepositCap
|
||||||
maxLtv: number
|
apy: {
|
||||||
liquidityRate: number
|
borrow: number
|
||||||
liquidationThreshold: number
|
deposit: number
|
||||||
|
}
|
||||||
|
ltv: {
|
||||||
|
max: number
|
||||||
|
liq: number
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,10 +107,15 @@ export const calculateAccountApr = (
|
|||||||
if (!asset) return BN_ZERO
|
if (!asset) return BN_ZERO
|
||||||
const price = prices.find(byDenom(lend.denom))?.amount ?? 0
|
const price = prices.find(byDenom(lend.denom))?.amount ?? 0
|
||||||
const amount = BN(lend.amount).shiftedBy(-asset.decimals)
|
const amount = BN(lend.amount).shiftedBy(-asset.decimals)
|
||||||
const apr =
|
const apy = lendingAssetsData.find((lendingAsset) => lendingAsset.asset.denom === lend.denom)
|
||||||
lendingAssetsData.find((lendingAsset) => lendingAsset.asset.denom === lend.denom)
|
?.apy.deposit
|
||||||
?.marketLiquidityRate ?? 0
|
|
||||||
const positionInterest = amount.multipliedBy(price).multipliedBy(apr).dividedBy(100)
|
if (!apy) return
|
||||||
|
|
||||||
|
const positionInterest = amount
|
||||||
|
.multipliedBy(price)
|
||||||
|
.multipliedBy(convertApyToApr(apy, 365))
|
||||||
|
.dividedBy(100)
|
||||||
totalLendsInterestValue = totalLendsInterestValue.plus(positionInterest)
|
totalLendsInterestValue = totalLendsInterestValue.plus(positionInterest)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -125,9 +130,11 @@ export const calculateAccountApr = (
|
|||||||
if (!asset) return BN_ZERO
|
if (!asset) return BN_ZERO
|
||||||
const price = prices.find(byDenom(debt.denom))?.amount ?? 0
|
const price = prices.find(byDenom(debt.denom))?.amount ?? 0
|
||||||
const amount = BN(debt.amount).shiftedBy(-asset.decimals)
|
const amount = BN(debt.amount).shiftedBy(-asset.decimals)
|
||||||
const apy =
|
const apy = borrowAssetsData.find((borrowAsset) => borrowAsset.asset.denom === debt.denom)?.apy
|
||||||
borrowAssetsData.find((borrowAsset) => borrowAsset.asset.denom === debt.denom)?.borrowRate ??
|
.borrow
|
||||||
0
|
|
||||||
|
if (!apy) return
|
||||||
|
|
||||||
const positionInterest = amount
|
const positionInterest = amount
|
||||||
.multipliedBy(price)
|
.multipliedBy(price)
|
||||||
.multipliedBy(convertApyToApr(apy, 365))
|
.multipliedBy(convertApyToApr(apy, 365))
|
||||||
|
@ -14,7 +14,10 @@ export function resolveMarketResponse(
|
|||||||
): Market {
|
): Market {
|
||||||
return {
|
return {
|
||||||
denom: marketResponse.denom,
|
denom: marketResponse.denom,
|
||||||
borrowRate: convertAprToApy(Number(marketResponse.borrow_rate), 365) * 100,
|
apy: {
|
||||||
|
borrow: convertAprToApy(Number(marketResponse.borrow_rate), 365) * 100,
|
||||||
|
deposit: convertAprToApy(Number(marketResponse.liquidity_rate), 365) * 100,
|
||||||
|
},
|
||||||
debtTotalScaled: marketResponse.debt_total_scaled,
|
debtTotalScaled: marketResponse.debt_total_scaled,
|
||||||
collateralTotalScaled: marketResponse.collateral_total_scaled,
|
collateralTotalScaled: marketResponse.collateral_total_scaled,
|
||||||
depositEnabled: assetParamsResponse.red_bank.deposit_enabled,
|
depositEnabled: assetParamsResponse.red_bank.deposit_enabled,
|
||||||
@ -24,9 +27,10 @@ export function resolveMarketResponse(
|
|||||||
used: BN(assetCapResponse.amount),
|
used: BN(assetCapResponse.amount),
|
||||||
max: BN(assetParamsResponse.deposit_cap),
|
max: BN(assetParamsResponse.deposit_cap),
|
||||||
},
|
},
|
||||||
maxLtv: Number(assetParamsResponse.max_loan_to_value),
|
ltv: {
|
||||||
liquidityRate: Number(marketResponse.liquidity_rate) * 100,
|
max: Number(assetParamsResponse.max_loan_to_value),
|
||||||
liquidationThreshold: Number(assetParamsResponse.liquidation_threshold),
|
liq: Number(assetParamsResponse.liquidation_threshold),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user