Moved Markets data to SWR (#749)

This commit is contained in:
Bob van der Helm 2024-01-26 16:55:45 +01:00 committed by GitHub
parent 7cfe05ebb7
commit a00c8e391b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
77 changed files with 604 additions and 810 deletions

View File

@ -1,41 +0,0 @@
import getTotalActiveEmissionValue from 'api/incentives/getTotalActiveEmissionValue'
import getMarket from 'api/markets/getMarket'
import getUnderlyingLiquidityAmount from 'api/markets/getMarketUnderlyingLiquidityAmount'
import getPrice from 'api/prices/getPrice'
import { byDenom } from 'utils/array'
import { SECONDS_IN_A_YEAR } from 'utils/constants'
import { BN } from 'utils/helpers'
export default async function calculateAssetIncentivesApy(
chainConfig: ChainConfig,
denom: string,
): Promise<BigNumber | null> {
try {
const [totalActiveEmissionValue, market] = await Promise.all([
getTotalActiveEmissionValue(chainConfig, denom),
getMarket(chainConfig, denom),
])
if (!totalActiveEmissionValue) return null
const [marketLiquidityAmount, assetPrice] = await Promise.all([
getUnderlyingLiquidityAmount(chainConfig, market),
getPrice(chainConfig, denom),
])
const assetDecimals = (chainConfig.assets.find(byDenom(denom)) as Asset).decimals
const marketLiquidityValue = BN(marketLiquidityAmount)
.shiftedBy(-assetDecimals)
.multipliedBy(assetPrice)
const marketReturns = BN(market.apy.deposit).multipliedBy(marketLiquidityValue)
const annualEmission = totalActiveEmissionValue.multipliedBy(SECONDS_IN_A_YEAR)
const totalAnnualReturnsValue = annualEmission.plus(marketReturns)
return totalAnnualReturnsValue.dividedBy(marketLiquidityValue).multipliedBy(100)
} catch (ex) {
console.error(ex)
return null
}
}

View File

@ -1,24 +0,0 @@
import { cacheFn, marketCache } from 'api/cache'
import { getParamsQueryClient, getRedBankQueryClient } from 'api/cosmwasm-client'
import { resolveMarketResponse } from 'utils/resolvers'
export default async function getMarket(chainConfig: ChainConfig, denom: string): Promise<Market> {
return cacheFn(() => fetchMarket(chainConfig, denom), marketCache, denom, 60)
}
async function fetchMarket(chainConfig: ChainConfig, denom: string) {
try {
const redBankClient = await getRedBankQueryClient(chainConfig)
const paramsClient = await getParamsQueryClient(chainConfig)
const [market, assetParams, assetCap] = await Promise.all([
redBankClient.market({ denom }),
paramsClient.assetParams({ denom }),
paramsClient.totalDeposit({ denom }),
])
return resolveMarketResponse(market, assetParams, assetCap)
} catch (ex) {
throw ex
}
}

View File

@ -1,35 +0,0 @@
import getMarketLiquidities from 'api/markets/getMarketLiquidities'
import getMarkets from 'api/markets/getMarkets'
import getPrices from 'api/prices/getPrices'
import { BN } from 'utils/helpers'
export default async function getMarketBorrowings(
chainConfig: ChainConfig,
): Promise<BorrowAsset[]> {
const liquidities = await getMarketLiquidities(chainConfig)
const borrowEnabledMarkets = (await getMarkets(chainConfig)).filter(
(market: Market) => market.borrowEnabled,
)
const prices = await getPrices(chainConfig)
const borrow: BorrowAsset[] = borrowEnabledMarkets.map((market) => {
const price = prices.find((coin) => coin.denom === market.denom)?.amount ?? '1'
const amount = liquidities.find((coin) => coin.denom === market.denom)?.amount ?? '0'
const asset = chainConfig.assets.find((asset) => asset.denom === market.denom)!
return {
...asset,
borrowRate: market.apy.borrow ?? 0,
liquidity: {
amount: BN(amount),
value: BN(amount).multipliedBy(price),
},
}
})
if (borrow) {
return borrow
}
return new Promise((_, reject) => reject('No data'))
}

View File

@ -1,31 +0,0 @@
import { cacheFn, underlyingDebtCache } from 'api/cache'
import { getRedBankQueryClient } from 'api/cosmwasm-client'
import getMarkets from 'api/markets/getMarkets'
import { BNCoin } from 'types/classes/BNCoin'
export default async function getMarketDebts(chainConfig: ChainConfig): Promise<BNCoin[]> {
try {
const markets: Market[] = await getMarkets(chainConfig)
const redBankQueryClient = await getRedBankQueryClient(chainConfig)
const debtQueries = markets.map((asset) =>
cacheFn(
() =>
redBankQueryClient.underlyingDebtAmount({
denom: asset.denom,
amountScaled: asset.debtTotalScaled,
}),
underlyingDebtCache,
`marketDebts/${asset.denom}/amount/${asset.debtTotalScaled}`,
60,
),
)
const debtsResults = await Promise.all(debtQueries)
return debtsResults.map<BNCoin>(
(debt, index) => new BNCoin({ denom: markets[index].denom, amount: debt }),
)
} catch (ex) {
throw ex
}
}

View File

@ -1,23 +0,0 @@
import getMarkets from 'api/markets/getMarkets'
import getUnderlyingLiquidityAmount from 'api/markets/getMarketUnderlyingLiquidityAmount'
import { BNCoin } from 'types/classes/BNCoin'
export default async function getMarketDeposits(chainConfig: ChainConfig): Promise<BNCoin[]> {
try {
const markets: Market[] = await getMarkets(chainConfig)
const depositQueries = markets.map((market) =>
getUnderlyingLiquidityAmount(chainConfig, market),
)
const depositsResults = await Promise.all(depositQueries)
return depositsResults.map<BNCoin>(
(deposit, index) =>
new BNCoin({
denom: markets[index].denom,
amount: deposit,
}),
)
} catch (ex) {
throw ex
}
}

View File

@ -1,30 +0,0 @@
import getMarketDebts from 'api/markets/getMarketDebts'
import getMarketDeposits from 'api/markets/getMarketDeposits'
import { BNCoin } from 'types/classes/BNCoin'
export default async function getMarketLiquidities(chainConfig: ChainConfig): Promise<BNCoin[]> {
const deposits = await getMarketDeposits(chainConfig)
const debts = await getMarketDebts(chainConfig)
const liquidity: BNCoin[] = deposits.map((deposit) => {
const debt = debts.find((debt) => debt.denom === deposit.denom)
if (debt) {
return new BNCoin({
denom: deposit.denom,
amount: deposit.amount.minus(debt.amount).toString(),
})
}
return new BNCoin({
denom: deposit.denom,
amount: '0',
})
})
if (liquidity) {
return liquidity
}
return new Promise((_, reject) => reject('No data'))
}

View File

@ -1,26 +0,0 @@
import { cacheFn, underlyingLiquidityAmountCache } from 'api/cache'
import { getRedBankQueryClient } from 'api/cosmwasm-client'
export default async function getUnderlyingLiquidityAmount(
chainConfig: ChainConfig,
market: Market,
): Promise<string> {
return cacheFn(
() => fetchUnderlyingLiquidityAmount(chainConfig, market),
underlyingLiquidityAmountCache,
`underlyingLiquidity/${market.denom}/amount/${market.collateralTotalScaled}`,
60,
)
}
async function fetchUnderlyingLiquidityAmount(chainConfig: ChainConfig, market: Market) {
try {
const client = await getRedBankQueryClient(chainConfig)
return await client.underlyingLiquidityAmount({
denom: market.denom,
amountScaled: market.collateralTotalScaled,
})
} catch (ex) {
throw ex
}
}

View File

@ -1,59 +0,0 @@
import { allParamsCache, cacheFn, marketsCache, totalDepositCache } from 'api/cache'
import { getParamsQueryClient, getRedBankQueryClient } from 'api/cosmwasm-client'
import {
AssetParamsBaseForAddr as AssetParams,
TotalDepositResponse,
} from 'types/generated/mars-params/MarsParams.types'
import { Market as RedBankMarket } from 'types/generated/mars-red-bank/MarsRedBank.types'
import { byDenom } from 'utils/array'
import iterateContractQuery from 'utils/iterateContractQuery'
import { resolveMarketResponse } from 'utils/resolvers'
export default async function getMarkets(chainConfig: ChainConfig): Promise<Market[]> {
try {
const redBankClient = await getRedBankQueryClient(chainConfig)
const paramsClient = await getParamsQueryClient(chainConfig)
const marketAssets = chainConfig.assets.filter((asset) => asset.isMarket)
const capQueries = marketAssets
.filter((asset) => asset.isMarket)
.map((asset) =>
cacheFn(
() => paramsClient.totalDeposit({ denom: asset.denom }),
totalDepositCache,
`chains/${chainConfig.id}/enabledMarkets/${asset.denom}`,
60,
),
)
const caps = await Promise.all(capQueries)
const [markets, assetParams, assetCaps] = await Promise.all([
cacheFn(
() => iterateContractQuery(redBankClient.markets),
marketsCache,
`chains/${chainConfig.id}/markets`,
60,
),
cacheFn(
async () => await iterateContractQuery(paramsClient.allAssetParams),
allParamsCache,
`chains/${chainConfig.id}/params`,
60,
),
Promise.all(capQueries),
])
return marketAssets.map((asset) =>
resolveMarketResponse(
markets.find(byDenom(asset.denom)) as RedBankMarket,
assetParams.find(byDenom(asset.denom)) as AssetParams,
assetCaps.find(byDenom(asset.denom)) as TotalDepositResponse,
),
)
} catch (ex) {
console.log(ex)
throw ex
}
}

View File

@ -1,9 +1,9 @@
import { useCallback, useMemo, useState } from 'react'
import AssetsSelect from 'components/Modals/AssetsSelect'
import SearchBar from 'components/common/SearchBar'
import Text from 'components/common/Text'
import useMarketBorrowings from 'hooks/markets/useMarketBorrowings'
import AssetsSelect from 'components/Modals/AssetsSelect'
import useMarkets from 'hooks/markets/useMarkets'
import useStore from 'store'
interface Props {
@ -14,16 +14,16 @@ interface Props {
export default function AddVaultAssetsModalContent(props: Props) {
const [searchString, setSearchString] = useState<string>('')
const { data: borrowAssets } = useMarketBorrowings()
const markets = useMarkets()
const filteredBorrowAssets: BorrowAsset[] = useMemo(() => {
return borrowAssets.filter(
(asset) =>
asset.name.toLowerCase().includes(searchString.toLowerCase()) ||
asset.denom.toLowerCase().includes(searchString.toLowerCase()) ||
asset.symbol.toLowerCase().includes(searchString.toLowerCase()),
const filteredMarkets: Market[] = useMemo(() => {
return markets.filter(
(market) =>
market.asset.name.toLowerCase().includes(searchString.toLowerCase()) ||
market.asset.denom.toLowerCase().includes(searchString.toLowerCase()) ||
market.asset.symbol.toLowerCase().includes(searchString.toLowerCase()),
)
}, [borrowAssets, searchString])
}, [markets, searchString])
function onChangeSearchString(value: string) {
setSearchString(value)
@ -31,21 +31,21 @@ export default function AddVaultAssetsModalContent(props: Props) {
const [poolAssets, stableAssets] = useMemo(
() =>
filteredBorrowAssets.reduce(
(acc, asset) => {
filteredMarkets.reduce(
(acc, market) => {
if (
asset.denom === props.vault.denoms.primary ||
asset.denom === props.vault.denoms.secondary
market.asset.denom === props.vault.denoms.primary ||
market.asset.denom === props.vault.denoms.secondary
) {
acc[0].push(asset)
} else if (asset.isStable) {
acc[1].push(asset)
acc[0].push(market.asset)
} else if (market.asset.isStable) {
acc[1].push(market.asset)
}
return acc
},
[[], []] as [BorrowAsset[], BorrowAsset[]],
[[], []] as [Asset[], Asset[]],
),
[filteredBorrowAssets, props.vault.denoms.primary, props.vault.denoms.secondary],
[filteredMarkets, props.vault.denoms.primary, props.vault.denoms.secondary],
)
const selectedDenoms = useStore((s) => s.addVaultBorrowingsModal?.selectedDenoms)

View File

@ -1,15 +1,16 @@
import { RowSelectionState } from '@tanstack/react-table'
import { useEffect, useMemo, useState } from 'react'
import useAssetSelectColumns from 'components/Modals/AssetsSelect/Columns/useAssetSelectColumns'
import Table from 'components/common/Table'
import useAssetSelectColumns from 'components/Modals/AssetsSelect/Columns/useAssetSelectColumns'
import useGetCoinValue from 'hooks/assets/useGetCoinValue'
import useMarketAssets from 'hooks/markets/useMarketAssets'
import useMarkets from 'hooks/markets/useMarkets'
import useStore from 'store'
import { BNCoin } from 'types/classes/BNCoin'
import { byDenom } from 'utils/array'
import { BN } from 'utils/helpers'
// TODO: Pass the market data directly here instead of the assets
interface Props {
assets: Asset[]
onChangeSelected: (selected: string[]) => void
@ -20,12 +21,11 @@ interface Props {
export default function AssetsSelect(props: Props) {
const { assets, onChangeSelected, selectedDenoms, isBorrow } = props
const columns = useAssetSelectColumns(isBorrow)
const { data: markets } = useMarketAssets()
const markets = useMarkets()
const getCoinValue = useGetCoinValue()
const defaultSelected = useMemo(() => {
const selectableAssets = assets
return selectableAssets.reduce(
return assets.reduce(
(acc, asset, index) => {
if (selectedDenoms?.includes(asset.denom)) {
acc[index] = true
@ -48,7 +48,7 @@ export default function AssetsSelect(props: Props) {
asset,
balance: balancesForAsset?.amount ?? '0',
value,
market: markets.find((market) => market.denom === asset.denom),
market: markets.find((market) => market.asset.denom === asset.denom),
}
})
}, [balances, assets, markets, getCoinValue])

View File

@ -16,7 +16,7 @@ import TokenInputWithSlider from 'components/common/TokenInput/TokenInputWithSli
import Modal from 'components/Modals/Modal'
import { BN_ZERO } from 'constants/math'
import useCurrentAccount from 'hooks/accounts/useCurrentAccount'
import useMarketAssets from 'hooks/markets/useMarketAssets'
import useMarkets from 'hooks/markets/useMarkets'
import useAutoLend from 'hooks/useAutoLend'
import useHealthComputer from 'hooks/useHealthComputer'
import useToggle from 'hooks/useToggle'
@ -91,7 +91,7 @@ function BorrowModal(props: Props) {
const isAutoLendEnabled = autoLendEnabledAccountIds.includes(account.id)
const { computeMaxBorrowAmount } = useHealthComputer(account)
const totalDebt = BN(getDebtAmount(modal))
const { data: marketAssets } = useMarketAssets()
const markets = useMarkets()
const [depositBalance, lendBalance] = useMemo(
() => [
@ -107,13 +107,13 @@ function BorrowModal(props: Props) {
)
const overpayExeedsCap = useMemo(() => {
const marketAsset = marketAssets.find(byDenom(asset.denom))
const marketAsset = markets.find(byDenom(asset.denom))
if (!marketAsset) return
const overpayAmount = totalDebtRepayAmount.minus(totalDebt)
const marketCapAfterOverpay = marketAsset.cap.used.plus(overpayAmount)
return marketAsset.cap.max.isLessThanOrEqualTo(marketCapAfterOverpay)
}, [marketAssets, asset.denom, totalDebt, totalDebtRepayAmount])
}, [markets, asset.denom, totalDebt, totalDebtRepayAmount])
const maxRepayAmount = useMemo(() => {
const maxBalance = repayFromWallet
@ -187,7 +187,7 @@ function BorrowModal(props: Props) {
? BN_ZERO
: computeMaxBorrowAmount(asset.denom, borrowToWallet ? 'wallet' : 'deposit')
return BigNumber.min(maxBorrowAmount, modal.marketData?.liquidity?.amount || 0)
return BigNumber.min(maxBorrowAmount, modal.marketData?.liquidity || 0)
}, [asset.denom, borrowToWallet, computeMaxBorrowAmount, isRepay, modal.marketData])
useEffect(() => {
@ -266,7 +266,7 @@ function BorrowModal(props: Props) {
<div className='flex gap-2'>
<FormattedNumber
className='text-xs'
amount={modal.marketData?.liquidity?.amount.toNumber() ?? 0}
amount={modal.marketData?.liquidity.toNumber() ?? 0}
options={{ decimals: asset.decimals, abbreviated: true, suffix: ` ${asset.symbol}` }}
animate
/>
@ -274,7 +274,7 @@ function BorrowModal(props: Props) {
className='text-xs'
coin={BNCoin.fromDenomAndBigNumber(
asset.denom,
modal.marketData?.liquidity?.amount ?? BN_ZERO,
modal.marketData?.liquidity ?? BN_ZERO,
)}
parentheses
/>

View File

@ -2,13 +2,13 @@ import React, { useMemo } from 'react'
import Button from 'components/common/Button'
import { ArrowRight } from 'components/common/Icons'
import LeverageSummary from 'components/Modals/HLS/Deposit/LeverageSummary'
import TokenInputWithSlider from 'components/common/TokenInput/TokenInputWithSlider'
import LeverageSummary from 'components/Modals/HLS/Deposit/LeverageSummary'
import { getLeveragedApy } from 'utils/math'
interface Props {
amount: BigNumber
asset: BorrowAsset
borrowMarket: Market
max: BigNumber
onChangeAmount: (amount: BigNumber) => void
onClickBtn: () => void
@ -21,15 +21,15 @@ interface Props {
export default function Leverage(props: Props) {
const apy = useMemo(() => {
if (!props.asset.borrowRate) return 0
return getLeveragedApy(props.baseApy, props.asset.borrowRate, props.leverage)
}, [props.asset.borrowRate, props.baseApy, props.leverage])
if (!props.borrowMarket.apy.borrow) return 0
return getLeveragedApy(props.baseApy, props.borrowMarket.apy.borrow, props.leverage)
}, [props.baseApy, props.borrowMarket.apy.borrow, props.leverage])
return (
<div id='item-1' className='flex-col gap-6 flex justify-between h-full p-4'>
<TokenInputWithSlider
amount={props.amount}
asset={props.asset}
asset={props.borrowMarket.asset}
max={props.max}
onChange={props.onChangeAmount}
maxText='Max borrow'
@ -40,7 +40,11 @@ export default function Leverage(props: Props) {
warningMessages={props.warningMessages}
/>
<div className='flex flex-col gap-6'>
<LeverageSummary asset={props.asset} positionValue={props.positionValue} apy={apy} />
<LeverageSummary
asset={props.borrowMarket.asset}
positionValue={props.positionValue}
apy={apy}
/>
<Button onClick={props.onClickBtn} text='Continue' rightIcon={<ArrowRight />} />
</div>
</div>

View File

@ -1,7 +1,7 @@
import React, { useMemo } from 'react'
import SummaryItems from 'components/common/SummaryItems'
import useBorrowAsset from 'hooks/useBorrowAsset'
import useMarket from 'hooks/markets/useMarket'
interface Props {
asset: Asset
@ -10,7 +10,7 @@ interface Props {
}
export default function LeverageSummary(props: Props) {
const borrowAsset = useBorrowAsset(props.asset.denom)
const market = useMarket(props.asset.denom)
const items: SummaryItem[] = useMemo(() => {
return [
@ -21,7 +21,7 @@ export default function LeverageSummary(props: Props) {
},
{
title: `Borrow APR ${props.asset.symbol}`,
amount: borrowAsset?.borrowRate || 0,
amount: market?.apy.borrow || 0,
options: { suffix: '%', minDecimals: 2, maxDecimals: 2 },
},
{
@ -30,7 +30,7 @@ export default function LeverageSummary(props: Props) {
options: { prefix: '$' },
},
]
}, [borrowAsset?.borrowRate, props.apy, props.asset.symbol, props.positionValue])
}, [market?.apy.borrow, props.apy, props.asset.symbol, props.positionValue])
return <SummaryItems items={items} />
}

View File

@ -4,13 +4,12 @@ import Button from 'components/common/Button'
import { ArrowRight } from 'components/common/Icons'
import AssetSummary from 'components/Modals/HLS/Deposit/Summary/AssetSummary'
import YourPosition from 'components/Modals/HLS/Deposit/Summary/YourPosition'
import useBorrowAsset from 'hooks/useBorrowAsset'
import { BNCoin } from 'types/classes/BNCoin'
interface Props {
apy: number
borrowAmount: BigNumber
borrowAsset: Asset
borrowMarket: Market
collateralAsset: Asset
depositAmount: BigNumber
leverage: number
@ -20,18 +19,14 @@ interface Props {
}
export default function Summary(props: Props) {
const borrowAsset = useBorrowAsset(props.borrowAsset.denom)
if (!borrowAsset) return null
return (
<div id='item-3' className='p-4 flex flex-col gap-4'>
<AssetSummary asset={props.collateralAsset} amount={props.depositAmount} />
<AssetSummary asset={borrowAsset} amount={props.borrowAmount} isBorrow />
<AssetSummary asset={props.borrowMarket.asset} amount={props.borrowAmount} isBorrow />
<YourPosition
positionValue={BNCoin.fromDenomAndBigNumber('usd', props.positionValue)}
baseApy={props.apy || 0}
borrowRate={borrowAsset.borrowRate || 0}
borrowRate={props.borrowMarket.apy.borrow || 0}
leverage={props.leverage}
/>
<Button

View File

@ -13,7 +13,7 @@ import useStore from 'store'
import { isAccountEmpty } from 'utils/accounts'
interface Props {
borrowAsset: BorrowAsset
borrowMarket: Market
collateralAsset: Asset
vaultAddress: string | null
strategy?: HLSStrategy
@ -42,7 +42,7 @@ export default function Controller(props: Props) {
walletCollateralAsset={walletCollateralAsset}
vault={vault}
collateralAsset={props.collateralAsset}
borrowAsset={props.borrowAsset}
borrowMarket={props.borrowMarket}
emptyHlsAccounts={emptyHlsAccounts}
hlsAccounts={hlsAccounts}
isOpen={isOpen}
@ -57,7 +57,7 @@ export default function Controller(props: Props) {
<StakingContent
walletCollateralAsset={walletCollateralAsset}
collateralAsset={props.collateralAsset}
borrowAsset={props.borrowAsset}
borrowMarket={props.borrowMarket}
emptyHlsAccounts={emptyHlsAccounts}
hlsAccounts={hlsAccounts}
isOpen={isOpen}
@ -73,7 +73,7 @@ export default function Controller(props: Props) {
}
interface ContentProps {
borrowAsset: BorrowAsset
borrowMarket: Market
collateralAsset: Asset
emptyHlsAccounts: Account[]
hlsAccounts: Account[]
@ -102,14 +102,14 @@ function Vault(props: VaultContentProps) {
} = useVaultController({
vault: props.vault,
collateralAsset: props.collateralAsset,
borrowAsset: props.borrowAsset,
borrowMarket: props.borrowMarket,
selectedAccount: props.selectedAccount,
})
const items = useAccordionItems({
apy: props.vault.apy || 0,
borrowAmount,
borrowAsset: props.borrowAsset,
borrowMarket: props.borrowMarket,
collateralAsset: props.collateralAsset,
depositAmount,
emptyHlsAccounts: props.emptyHlsAccounts,
@ -148,13 +148,13 @@ function StakingContent(props: StakingContentProps) {
execute,
} = useStakingController({
collateralAsset: props.collateralAsset,
borrowAsset: props.borrowAsset,
borrowMarket: props.borrowMarket,
selectedAccount: props.selectedAccount,
})
const items = useAccordionItems({
borrowAmount,
borrowAsset: props.borrowAsset,
borrowMarket: props.borrowMarket,
collateralAsset: props.collateralAsset,
depositAmount,
emptyHlsAccounts: props.emptyHlsAccounts,

View File

@ -26,7 +26,7 @@ import {
interface Props {
apy: number
borrowAmount: BigNumber
borrowAsset: BorrowAsset
borrowMarket: Market
collateralAsset: Asset
depositAmount: BigNumber
emptyHlsAccounts: Account[]
@ -56,18 +56,24 @@ export default function useAccordionItems(props: Props) {
}, [props.strategy])
const borrowLiquidity = useMemo(
() => props.borrowAsset.liquidity?.amount || BN_ZERO,
[props.borrowAsset.liquidity?.amount],
() => props.borrowMarket.liquidity || BN_ZERO,
[props.borrowMarket.liquidity],
)
const additionalDepositFromSwap = useMemo(() => {
const value = getCoinValue(
BNCoin.fromDenomAndBigNumber(props.borrowAsset.denom, props.borrowAmount),
BNCoin.fromDenomAndBigNumber(props.borrowMarket.asset.denom, props.borrowAmount),
prices,
assets,
)
return getCoinAmount(props.collateralAsset.denom, value, prices, assets)
}, [assets, prices, props.borrowAmount, props.borrowAsset.denom, props.collateralAsset.denom])
}, [
assets,
prices,
props.borrowAmount,
props.borrowMarket.asset.denom,
props.collateralAsset.denom,
])
const collateralWarningMessages = useMemo(() => {
const messages: string[] = []
@ -96,16 +102,23 @@ export default function useAccordionItems(props: Props) {
if (props.borrowAmount.isGreaterThan(props.maxBorrowAmount)) {
messages.push(
getHealthFactorMessage(props.borrowAsset.denom, props.maxBorrowAmount, 'borrow', assets),
getHealthFactorMessage(
props.borrowMarket.asset.denom,
props.maxBorrowAmount,
'borrow',
assets,
),
)
}
if (props.borrowAmount.isGreaterThan(borrowLiquidity)) {
messages.push(getLiquidityMessage(props.borrowAsset.denom, borrowLiquidity, assets))
messages.push(getLiquidityMessage(props.borrowMarket.asset.denom, borrowLiquidity, assets))
}
if (additionalDepositFromSwap.plus(props.depositAmount).isGreaterThan(props.maxBorrowAmount)) {
messages.push(getDepositCapMessage(props.borrowAsset.denom, depositCapLeft, 'borrow', assets))
messages.push(
getDepositCapMessage(props.borrowMarket.asset.denom, depositCapLeft, 'borrow', assets),
)
}
return messages
@ -115,7 +128,7 @@ export default function useAccordionItems(props: Props) {
borrowLiquidity,
depositCapLeft,
props.borrowAmount,
props.borrowAsset.denom,
props.borrowMarket.asset.denom,
props.depositAmount,
props.maxBorrowAmount,
])
@ -160,7 +173,7 @@ export default function useAccordionItems(props: Props) {
<Leverage
leverage={props.leverage}
amount={props.borrowAmount}
asset={props.borrowAsset}
borrowMarket={props.borrowMarket}
onChangeAmount={props.onChangeDebt}
onClickBtn={() => props.toggleIsOpen(2)}
max={props.maxBorrowAmount}
@ -228,7 +241,7 @@ export default function useAccordionItems(props: Props) {
leverage={props.leverage}
positionValue={props.positionValue}
collateralAsset={props.collateralAsset}
borrowAsset={props.borrowAsset}
borrowMarket={props.borrowMarket}
apy={props.apy}
onClickBtn={props.execute}
disabled={

View File

@ -10,17 +10,17 @@ import { SWAP_FEE_BUFFER } from 'utils/constants'
import { BN } from 'utils/helpers'
interface Props {
borrowAsset: Asset
borrowMarket: Market
collateralAsset: Asset
selectedAccount: Account
}
export default function useStakingController(props: Props) {
const { collateralAsset, borrowAsset, selectedAccount } = props
const { collateralAsset, borrowMarket, selectedAccount } = props
const addToStakingStrategy = useStore((s) => s.addToStakingStrategy)
const { data: swapValueLoss } = useSwapValueLoss(
props.borrowAsset.denom,
props.borrowMarket.asset.denom,
props.collateralAsset.denom,
)
const {
@ -33,34 +33,39 @@ export default function useStakingController(props: Props) {
actions,
} = useDepositHlsVault({
collateralDenom: collateralAsset.denom,
borrowDenom: borrowAsset.denom,
borrowDenom: borrowMarket.asset.denom,
})
const { updatedAccount, addDeposits } = useUpdatedAccount(selectedAccount)
const { computeMaxBorrowAmount } = useHealthComputer(updatedAccount)
const maxBorrowAmount = useMemo(() => {
return computeMaxBorrowAmount(props.borrowAsset.denom, {
return computeMaxBorrowAmount(props.borrowMarket.asset.denom, {
swap: {
denom_out: props.collateralAsset.denom,
slippage: BN(swapValueLoss).plus(SWAP_FEE_BUFFER).toString(),
},
})
}, [computeMaxBorrowAmount, props.borrowAsset.denom, props.collateralAsset.denom, swapValueLoss])
}, [
computeMaxBorrowAmount,
props.borrowMarket.asset.denom,
props.collateralAsset.denom,
swapValueLoss,
])
const execute = useCallback(() => {
useStore.setState({ hlsModal: null })
addToStakingStrategy({
actions,
accountId: selectedAccount.id,
borrowCoin: BNCoin.fromDenomAndBigNumber(borrowAsset.denom, borrowAmount),
borrowCoin: BNCoin.fromDenomAndBigNumber(borrowMarket.asset.denom, borrowAmount),
depositCoin: BNCoin.fromDenomAndBigNumber(collateralAsset.denom, depositAmount),
})
}, [
actions,
addToStakingStrategy,
borrowAmount,
borrowAsset.denom,
borrowMarket.asset.denom,
collateralAsset.denom,
depositAmount,
selectedAccount.id,

View File

@ -8,14 +8,14 @@ import useStore from 'store'
import { BNCoin } from 'types/classes/BNCoin'
interface Props {
borrowAsset: Asset
borrowMarket: Market
collateralAsset: Asset
selectedAccount: Account
vault: Vault
}
export default function useVaultController(props: Props) {
const { vault, collateralAsset, borrowAsset, selectedAccount } = props
const { vault, collateralAsset, borrowMarket, selectedAccount } = props
const depositIntoVault = useStore((s) => s.depositIntoVault)
@ -28,14 +28,14 @@ export default function useVaultController(props: Props) {
positionValue,
} = useDepositHlsVault({
collateralDenom: collateralAsset.denom,
borrowDenom: borrowAsset.denom,
borrowDenom: borrowMarket.asset.denom,
})
const { actions } = useDepositVault({
vault,
reclaims: [],
deposits: [BNCoin.fromDenomAndBigNumber(collateralAsset.denom, depositAmount)],
borrowings: [BNCoin.fromDenomAndBigNumber(borrowAsset.denom, borrowAmount)],
borrowings: [BNCoin.fromDenomAndBigNumber(borrowMarket.asset.denom, borrowAmount)],
kind: 'high_levered_strategy',
})
@ -43,17 +43,17 @@ export default function useVaultController(props: Props) {
const { computeMaxBorrowAmount } = useHealthComputer(updatedAccount)
const maxBorrowAmount = useMemo(() => {
return computeMaxBorrowAmount(props.borrowAsset.denom, {
return computeMaxBorrowAmount(props.borrowMarket.asset.denom, {
vault: { address: props.vault?.address },
}).plus(borrowAmount)
}, [borrowAmount, computeMaxBorrowAmount, props.borrowAsset.denom, props.vault?.address])
}, [borrowAmount, computeMaxBorrowAmount, props.borrowMarket.asset.denom, props.vault?.address])
const execute = useCallback(() => {
depositIntoVault({
accountId: selectedAccount.id,
actions,
deposits: [BNCoin.fromDenomAndBigNumber(collateralAsset.denom, depositAmount)],
borrowings: [BNCoin.fromDenomAndBigNumber(borrowAsset.denom, borrowAmount)],
borrowings: [BNCoin.fromDenomAndBigNumber(borrowMarket.asset.denom, borrowAmount)],
isCreate: true,
kind: 'high_levered_strategy',
})
@ -63,7 +63,7 @@ export default function useVaultController(props: Props) {
borrowAmount,
depositAmount,
depositIntoVault,
borrowAsset.denom,
borrowMarket.asset.denom,
collateralAsset.denom,
selectedAccount.id,
])
@ -75,12 +75,12 @@ export default function useVaultController(props: Props) {
simulateVaultDeposit(
vault.address,
[BNCoin.fromDenomAndBigNumber(collateralAsset.denom, amount)],
[BNCoin.fromDenomAndBigNumber(borrowAsset.denom, borrowAmount)],
[BNCoin.fromDenomAndBigNumber(borrowMarket.asset.denom, borrowAmount)],
)
},
[
borrowAmount,
borrowAsset,
borrowMarket,
collateralAsset,
vault.address,
setDepositAmount,
@ -95,11 +95,11 @@ export default function useVaultController(props: Props) {
simulateVaultDeposit(
vault.address,
[BNCoin.fromDenomAndBigNumber(collateralAsset.denom, depositAmount)],
[BNCoin.fromDenomAndBigNumber(borrowAsset.denom, amount)],
[BNCoin.fromDenomAndBigNumber(borrowMarket.asset.denom, amount)],
)
},
[
borrowAsset,
borrowMarket,
collateralAsset,
depositAmount,
vault.address,

View File

@ -1,8 +1,8 @@
import React, { useCallback, useMemo, useState } from 'react'
import Button from 'components/common/Button'
import LeverageSummary from 'components/Modals/HLS/Deposit/LeverageSummary'
import TokenInputWithSlider from 'components/common/TokenInput/TokenInputWithSlider'
import LeverageSummary from 'components/Modals/HLS/Deposit/LeverageSummary'
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
import { LocalStorageKeys } from 'constants/localStorageKeys'
import { BN_ZERO } from 'constants/math'
@ -23,7 +23,7 @@ import { getDepositCapMessage, getHealthFactorMessage, getLiquidityMessage } fro
interface Props {
account: HLSAccountWithStrategy
action: HlsStakingManageAction
borrowAsset: BorrowAsset
borrowMarket: Market
collateralAsset: Asset
}
@ -42,19 +42,24 @@ export default function ChangeLeverage(props: Props) {
const changeHlsStakingLeverage = useStore((s) => s.changeHlsStakingLeverage)
const { computeMaxBorrowAmount } = useHealthComputer(props.account)
const previousDebt: BigNumber = useMemo(
() => props.account.debts.find(byDenom(props.borrowAsset.denom))?.amount || BN_ZERO,
[props.account.debts, props.borrowAsset.denom],
() => props.account.debts.find(byDenom(props.borrowMarket.asset.denom))?.amount || BN_ZERO,
[props.account.debts, props.borrowMarket.asset.denom],
)
const [currentDebt, setAmount] = useState(previousDebt)
const maxBorrowAmount = useMemo(() => {
return computeMaxBorrowAmount(props.borrowAsset.denom, {
return computeMaxBorrowAmount(props.borrowMarket.asset.denom, {
swap: {
denom_out: props.collateralAsset.denom,
slippage: SWAP_FEE_BUFFER.toString(),
},
}).plus(previousDebt)
}, [computeMaxBorrowAmount, previousDebt, props.borrowAsset.denom, props.collateralAsset.denom])
}, [
computeMaxBorrowAmount,
previousDebt,
props.borrowMarket.asset.denom,
props.collateralAsset.denom,
])
const onChangeAmount = useCallback(
(currentDebt: BigNumber) => {
@ -62,19 +67,22 @@ export default function ChangeLeverage(props: Props) {
if (currentDebt.isLessThan(previousDebt)) {
simulateHlsStakingWithdraw(
props.collateralAsset.denom,
props.borrowAsset.denom,
props.borrowMarket.asset.denom,
previousDebt.minus(currentDebt),
)
} else {
simulateHlsStakingDeposit(
BNCoin.fromDenomAndBigNumber(props.collateralAsset.denom, BN_ZERO),
BNCoin.fromDenomAndBigNumber(props.borrowAsset.denom, currentDebt.minus(previousDebt)),
BNCoin.fromDenomAndBigNumber(
props.borrowMarket.asset.denom,
currentDebt.minus(previousDebt),
),
)
}
},
[
previousDebt,
props.borrowAsset.denom,
props.borrowMarket.asset.denom,
props.collateralAsset.denom,
simulateHlsStakingDeposit,
simulateHlsStakingWithdraw,
@ -98,7 +106,7 @@ export default function ChangeLeverage(props: Props) {
previousDebt,
currentDebt,
props.collateralAsset.denom,
props.borrowAsset.denom,
props.borrowMarket.asset.denom,
slippage,
prices,
assets,
@ -108,7 +116,7 @@ export default function ChangeLeverage(props: Props) {
currentDebt,
previousDebt,
props.collateralAsset.denom,
props.borrowAsset.denom,
props.borrowMarket.asset.denom,
props.account.id,
slippage,
prices,
@ -127,22 +135,22 @@ export default function ChangeLeverage(props: Props) {
)
const apy = useMemo(() => {
if (!props.borrowAsset.borrowRate || !props.account.strategy.apy) return 0
return getLeveragedApy(props.account.strategy.apy, props.borrowAsset.borrowRate, leverage)
}, [leverage, props.account.strategy.apy, props.borrowAsset.borrowRate])
if (!props.borrowMarket.apy.borrow || !props.account.strategy.apy) return 0
return getLeveragedApy(props.account.strategy.apy, props.borrowMarket.apy.borrow, leverage)
}, [leverage, props.account.strategy.apy, props.borrowMarket.apy.borrow])
const warningMessages = useMemo(() => {
const messages: string[] = []
const borrowLiquidity = props.borrowAsset.liquidity?.amount || BN_ZERO
const borrowLiquidity = props.borrowMarket.liquidity || BN_ZERO
if (borrowLiquidity.isLessThan(currentDebt.minus(previousDebt))) {
messages.push(getLiquidityMessage(props.borrowAsset.denom, borrowLiquidity, assets))
messages.push(getLiquidityMessage(props.borrowMarket.asset.denom, borrowLiquidity, assets))
}
if (maxBorrowAmount.isLessThan(currentDebt)) {
messages.push(
getHealthFactorMessage(props.borrowAsset.denom, maxBorrowAmount, 'borrow', assets),
getHealthFactorMessage(props.borrowMarket.asset.denom, maxBorrowAmount, 'borrow', assets),
)
}
@ -160,8 +168,8 @@ export default function ChangeLeverage(props: Props) {
depositCapLeft,
maxBorrowAmount,
previousDebt,
props.borrowAsset.denom,
props.borrowAsset.liquidity?.amount,
props.borrowMarket.asset.denom,
props.borrowMarket.liquidity,
props.collateralAsset.denom,
])
@ -169,7 +177,7 @@ export default function ChangeLeverage(props: Props) {
<>
<TokenInputWithSlider
amount={currentDebt}
asset={props.borrowAsset}
asset={props.borrowMarket.asset}
max={maxBorrowAmount}
onChange={onChangeAmount}
maxText='Max borrow'
@ -180,7 +188,7 @@ export default function ChangeLeverage(props: Props) {
warningMessages={warningMessages}
/>
<div className='flex flex-col gap-6'>
<LeverageSummary asset={props.borrowAsset} positionValue={positionValue} apy={apy} />
<LeverageSummary asset={props.borrowMarket.asset} positionValue={positionValue} apy={apy} />
<Button
onClick={handleOnClick}
text='Confirm'

View File

@ -10,7 +10,7 @@ import TokenInputWithSlider from 'components/common/TokenInput/TokenInputWithSli
import { BN_ZERO } from 'constants/math'
import useAllAssets from 'hooks/assets/useAllAssets'
import useDepositActions from 'hooks/hls/useDepositActions'
import useBorrowAsset from 'hooks/useBorrowAsset'
import useMarket from 'hooks/markets/useMarket'
import useCurrentWalletBalance from 'hooks/useCurrentWalletBalance'
import useHealthComputer from 'hooks/useHealthComputer'
import usePrices from 'hooks/usePrices'
@ -32,7 +32,7 @@ import {
interface Props {
account: HLSAccountWithStrategy
action: HlsStakingManageAction
borrowAsset: BorrowAsset
borrowMarket: Market
collateralAsset: Asset
}
@ -48,7 +48,7 @@ export default function Deposit(props: Props) {
useCurrentWalletBalance(props.collateralAsset.denom)?.amount || '0',
)
const addToStakingStrategy = useStore((s) => s.addToStakingStrategy)
const borrowRate = useBorrowAsset(props.borrowAsset.denom)?.borrowRate || 0
const borrowRate = useMarket(props.borrowMarket.asset.denom)?.apy.borrow || 0
const currentLeverage = useMemo(
() => calculateAccountLeverage(props.account, prices, assets).toNumber(),
@ -72,10 +72,10 @@ export default function Deposit(props: Props) {
const borrowCoin = useMemo(
() =>
BNCoin.fromDenomAndBigNumber(
props.borrowAsset.denom,
addedDebts.find(byDenom(props.borrowAsset.denom))?.amount || BN_ZERO,
props.borrowMarket.asset.denom,
addedDebts.find(byDenom(props.borrowMarket.asset.denom))?.amount || BN_ZERO,
),
[addedDebts, props.borrowAsset.denom],
[addedDebts, props.borrowMarket.asset.denom],
)
const warningMessages = useMemo(() => {
@ -105,22 +105,22 @@ export default function Deposit(props: Props) {
])
const maxBorrowAmount = useMemo(
() => computeMaxBorrowAmount(props.borrowAsset.denom, 'deposit'),
[computeMaxBorrowAmount, props.borrowAsset.denom],
() => computeMaxBorrowAmount(props.borrowMarket.asset.denom, 'deposit'),
[computeMaxBorrowAmount, props.borrowMarket.asset.denom],
)
const borrowWarningMessages = useMemo(() => {
let messages: string[] = []
if (borrowCoin.amount.isGreaterThan(maxBorrowAmount)) {
messages.push(
getHealthFactorMessage(props.borrowAsset.denom, maxBorrowAmount, 'borrow', assets),
getHealthFactorMessage(props.borrowMarket.asset.denom, maxBorrowAmount, 'borrow', assets),
)
}
const borrowLiquidity = props.borrowAsset.liquidity?.amount || BN_ZERO
const borrowLiquidity = props.borrowMarket.liquidity || BN_ZERO
if (borrowCoin.amount.isGreaterThan(borrowLiquidity)) {
messages.push(getLiquidityMessage(props.borrowAsset.denom, borrowLiquidity, assets))
messages.push(getLiquidityMessage(props.borrowMarket.asset.denom, borrowLiquidity, assets))
}
return messages
@ -128,15 +128,15 @@ export default function Deposit(props: Props) {
assets,
borrowCoin.amount,
maxBorrowAmount,
props.borrowAsset.denom,
props.borrowAsset.liquidity?.amount,
props.borrowMarket.asset.denom,
props.borrowMarket.liquidity,
])
const actions = useDepositActions({ depositCoin, borrowCoin })
const currentDebt: BigNumber = useMemo(
() => props.account.debts.find(byDenom(props.borrowAsset.denom))?.amount || BN_ZERO,
[props.account.debts, props.borrowAsset.denom],
() => props.account.debts.find(byDenom(props.borrowMarket.asset.denom))?.amount || BN_ZERO,
[props.account.debts, props.borrowMarket.asset.denom],
)
const handleDeposit = useCallback(() => {
@ -160,19 +160,19 @@ export default function Deposit(props: Props) {
assets,
)
const borrowValue = BN(currentLeverage - 1).times(depositValue)
additionalDebt = getCoinAmount(props.borrowAsset.denom, borrowValue, prices, assets)
additionalDebt = getCoinAmount(props.borrowMarket.asset.denom, borrowValue, prices, assets)
}
simulateHlsStakingDeposit(
BNCoin.fromDenomAndBigNumber(props.collateralAsset.denom, amount),
BNCoin.fromDenomAndBigNumber(props.borrowAsset.denom, additionalDebt),
BNCoin.fromDenomAndBigNumber(props.borrowMarket.asset.denom, additionalDebt),
)
},
[
currentLeverage,
keepLeverage,
prices,
props.borrowAsset.denom,
props.borrowMarket.asset.denom,
props.collateralAsset.denom,
simulateHlsStakingDeposit,
assets,
@ -197,18 +197,18 @@ export default function Deposit(props: Props) {
amount: borrowCoin.amount.toNumber(),
warningMessages: borrowWarningMessages,
options: {
suffix: ` ${props.borrowAsset.symbol}`,
suffix: ` ${props.borrowMarket.asset.symbol}`,
abbreviated: true,
decimals: props.borrowAsset.decimals,
decimals: props.borrowMarket.asset.decimals,
},
},
{
title: 'New Debt Amount',
amount: currentDebt.plus(borrowCoin.amount).toNumber(),
options: {
suffix: ` ${props.borrowAsset.symbol}`,
suffix: ` ${props.borrowMarket.asset.symbol}`,
abbreviated: true,
decimals: props.borrowAsset.decimals,
decimals: props.borrowMarket.asset.decimals,
},
},
]
@ -220,8 +220,8 @@ export default function Deposit(props: Props) {
borrowWarningMessages,
currentDebt,
keepLeverage,
props.borrowAsset.decimals,
props.borrowAsset.symbol,
props.borrowMarket.asset.decimals,
props.borrowMarket.asset.symbol,
],
)

View File

@ -16,25 +16,25 @@ import { getNoBalanceInWalletMessage } from 'utils/messages'
interface Props {
account: Account
action: HlsStakingManageAction
borrowAsset: Asset
borrowMarket: Market
collateralAsset: Asset
}
export default function Repay(props: Props) {
const { removeDebts, removedDebts } = useUpdatedAccount(props.account)
const borrowAssetAmountInWallet = BN(
useCurrentWalletBalance(props.borrowAsset.denom)?.amount || '0',
useCurrentWalletBalance(props.borrowMarket.asset.denom)?.amount || '0',
)
const repay = useStore((s) => s.repay)
const currentDebt: BigNumber = useMemo(
() => props.account.debts.find(byDenom(props.borrowAsset.denom))?.amount || BN_ZERO,
[props.account.debts, props.borrowAsset.denom],
() => props.account.debts.find(byDenom(props.borrowMarket.asset.denom))?.amount || BN_ZERO,
[props.account.debts, props.borrowMarket.asset.denom],
)
const repayAmount: BigNumber = useMemo(
() => removedDebts.find(byDenom(props.borrowAsset.denom))?.amount || BN_ZERO,
[removedDebts, props.borrowAsset.denom],
() => removedDebts.find(byDenom(props.borrowMarket.asset.denom))?.amount || BN_ZERO,
[removedDebts, props.borrowMarket.asset.denom],
)
const maxRepayAmount = useMemo(
@ -48,51 +48,51 @@ export default function Repay(props: Props) {
title: 'Total Debt Repayable',
amount: currentDebt.toNumber(),
options: {
suffix: ` ${props.borrowAsset.symbol}`,
suffix: ` ${props.borrowMarket.asset.symbol}`,
abbreviated: true,
decimals: props.borrowAsset.decimals,
decimals: props.borrowMarket.asset.decimals,
},
},
{
title: 'New Debt Amount',
amount: currentDebt.minus(repayAmount).toNumber(),
options: {
suffix: ` ${props.borrowAsset.symbol}`,
suffix: ` ${props.borrowMarket.asset.symbol}`,
abbreviated: true,
decimals: props.borrowAsset.decimals,
decimals: props.borrowMarket.asset.decimals,
},
},
],
[currentDebt, props.borrowAsset.decimals, props.borrowAsset.symbol, repayAmount],
[currentDebt, props.borrowMarket.asset.decimals, props.borrowMarket.asset.symbol, repayAmount],
)
const handleRepay = useCallback(() => {
useStore.setState({ hlsManageModal: null })
repay({
accountId: props.account.id,
coin: BNCoin.fromDenomAndBigNumber(props.borrowAsset.denom, repayAmount),
coin: BNCoin.fromDenomAndBigNumber(props.borrowMarket.asset.denom, repayAmount),
fromWallet: true,
})
}, [props.account.id, props.borrowAsset.denom, repay, repayAmount])
}, [props.account.id, props.borrowMarket.asset.denom, repay, repayAmount])
const handleOnChange = useCallback(
(amount: BigNumber) =>
removeDebts([BNCoin.fromDenomAndBigNumber(props.borrowAsset.denom, amount)]),
[props.borrowAsset.denom, removeDebts],
removeDebts([BNCoin.fromDenomAndBigNumber(props.borrowMarket.asset.denom, amount)]),
[props.borrowMarket.asset.denom, removeDebts],
)
const warningMessages = useMemo(() => {
if (borrowAssetAmountInWallet.isZero()) {
return [getNoBalanceInWalletMessage(props.borrowAsset.symbol)]
return [getNoBalanceInWalletMessage(props.borrowMarket.asset.symbol)]
}
return []
}, [borrowAssetAmountInWallet, props.borrowAsset.symbol])
}, [borrowAssetAmountInWallet, props.borrowMarket.asset.symbol])
return (
<>
<TokenInputWithSlider
amount={repayAmount}
asset={props.borrowAsset}
asset={props.borrowMarket.asset}
max={maxRepayAmount}
onChange={handleOnChange}
maxText='In Wallet'

View File

@ -14,7 +14,6 @@ import { getHealthFactorMessage } from 'utils/messages'
interface Props {
account: Account
action: HlsStakingManageAction
borrowAsset: Asset
collateralAsset: Asset
}

View File

@ -8,23 +8,23 @@ import Withdraw from 'components/Modals/HLS/Manage/Withdraw'
import ModalContentWithSummary from 'components/Modals/ModalContentWithSummary'
import useAccount from 'hooks/accounts/useAccount'
import useAsset from 'hooks/assets/useAsset'
import useBorrowAsset from 'hooks/useBorrowAsset'
import useMarket from 'hooks/markets/useMarket'
import useStore from 'store'
export default function HlsManageModalController() {
const modal = useStore((s) => s.hlsManageModal)
const { data: account } = useAccount(modal?.accountId)
const collateralAsset = useAsset(modal?.staking.strategy.denoms.deposit || '')
const borrowAsset = useBorrowAsset(modal?.staking.strategy.denoms.borrow || '')
const market = useMarket(modal?.staking.strategy.denoms.borrow || '')
if (!modal || !collateralAsset || !borrowAsset || !account) return null
if (!modal || !collateralAsset || !market || !account) return null
return (
<HlsModal
account={{ ...account, strategy: modal.staking.strategy } as HLSAccountWithStrategy}
action={modal.staking.action}
collateralAsset={collateralAsset}
borrowAsset={borrowAsset}
borrowMarket={market}
/>
)
}
@ -32,12 +32,11 @@ export default function HlsManageModalController() {
interface Props {
account: HLSAccountWithStrategy
action: HlsStakingManageAction
borrowAsset: BorrowAsset
borrowMarket: Market
collateralAsset: Asset
}
function HlsModal(props: Props) {
const updatedAccount = useStore((s) => s.updatedAccount)
function handleClose() {
useStore.setState({ hlsManageModal: null })
}
@ -65,7 +64,7 @@ function HlsModal(props: Props) {
<Header
action={props.action}
primaryAsset={props.collateralAsset}
secondaryAsset={props.borrowAsset}
secondaryAsset={props.borrowMarket.asset}
/>
}
onClose={handleClose}

View File

@ -1,10 +1,10 @@
import React from 'react'
import Modal from 'components/Modals/Modal'
import Content from 'components/Modals/HLS/Deposit'
import Header from 'components/Modals/HLS/Header'
import Modal from 'components/Modals/Modal'
import useAsset from 'hooks/assets/useAsset'
import useBorrowAsset from 'hooks/useBorrowAsset'
import useMarket from 'hooks/markets/useMarket'
import useStore from 'store'
export default function HlsModalController() {
@ -14,7 +14,7 @@ export default function HlsModalController() {
modal?.vault?.denoms.primary || modal?.strategy?.denoms.deposit || '',
)
const secondaryAsset = useBorrowAsset(modal?.strategy?.denoms.borrow || '')
const secondaryAsset = useMarket(modal?.strategy?.denoms.borrow || '')
if (!primaryAsset || !secondaryAsset) return null
@ -41,7 +41,7 @@ export default function HlsModalController() {
interface Props {
primaryAsset: Asset
secondaryAsset: BorrowAsset
secondaryAsset: Market
strategy?: HLSStrategy
vaultAddress: string | null
}
@ -53,7 +53,9 @@ function HlsModal(props: Props) {
return (
<Modal
header={<Header primaryAsset={props.primaryAsset} secondaryAsset={props.secondaryAsset} />}
header={
<Header primaryAsset={props.primaryAsset} secondaryAsset={props.secondaryAsset.asset} />
}
headerClassName='gradient-header pl-2 pr-2.5 py-3 border-b-white/5 border-b'
contentClassName='flex flex-col p-6'
modalClassName='max-w-modal-md'
@ -61,7 +63,7 @@ function HlsModal(props: Props) {
>
<Content
collateralAsset={props.primaryAsset}
borrowAsset={props.secondaryAsset}
borrowMarket={props.secondaryAsset}
vaultAddress={props.vaultAddress}
strategy={props.strategy}
/>

View File

@ -12,7 +12,7 @@ import TokenInput from 'components/common/TokenInput'
import { BN_ZERO } from 'constants/math'
import { ORACLE_DENOM } from 'constants/oracle'
import useAllAssets from 'hooks/assets/useAllAssets'
import useMarketAssets from 'hooks/markets/useMarketAssets'
import useMarkets from 'hooks/markets/useMarkets'
import useHealthComputer from 'hooks/useHealthComputer'
import usePrices from 'hooks/usePrices'
import useStore from 'store'
@ -39,7 +39,7 @@ export interface VaultBorrowingsProps {
export default function VaultBorrowings(props: VaultBorrowingsProps) {
const assets = useAllAssets()
const { borrowings, onChangeBorrowings } = props
const { data: marketAssets } = useMarketAssets()
const markets = useMarkets()
const { data: prices } = usePrices()
const vaultModal = useStore((s) => s.vaultModal)
const depositIntoVault = useStore((s) => s.depositIntoVault)
@ -227,7 +227,8 @@ export default function VaultBorrowings(props: VaultBorrowingsProps) {
</div>
{props.borrowings.map((coin) => {
const asset = assets.find(byDenom(coin.denom))
const borrowRate = marketAssets?.find((market) => market.denom === coin.denom)?.apy.borrow
const borrowRate = markets?.find((market) => market.asset.denom === coin.denom)?.apy
.borrow
if (!asset || !borrowRate)
return <React.Fragment key={`borrow-rate-${coin.denom}`}></React.Fragment>

View File

@ -13,7 +13,7 @@ import Value, {
VALUE_META,
valueBalancesSortingFn,
} from 'components/account/AccountBalancesTable/Columns/Value'
import useMarketAssets from 'hooks/markets/useMarketAssets'
import useMarkets from 'hooks/markets/useMarkets'
import useHealthComputer from 'hooks/useHealthComputer'
import useStore from 'store'
@ -21,7 +21,8 @@ export default function useAccountBalancesColumns(
account: Account,
showLiquidationPrice?: boolean,
) {
const { data: markets } = useMarketAssets()
const markets = useMarkets()
const updatedAccount = useStore((s) => s.updatedAccount)
const { computeLiquidationPrice } = useHealthComputer(updatedAccount ?? account)

View File

@ -2,16 +2,16 @@ import BigNumber from 'bignumber.js'
import classNames from 'classnames'
import { useMemo } from 'react'
import useBorrowMarketAssetsTableData from 'components/borrow/Table/useBorrowMarketAssetsTableData'
import DisplayCurrency from 'components/common/DisplayCurrency'
import { FormattedNumber } from 'components/common/FormattedNumber'
import { ArrowRight } from 'components/common/Icons'
import Text from 'components/common/Text'
import useLendingMarketAssetsTableData from 'components/earn/lend/Table/useLendingMarketAssetsTableData'
import { BN_ZERO, MAX_AMOUNT_DECIMALS } from 'constants/math'
import { ORACLE_DENOM } from 'constants/oracle'
import useAllAssets from 'hooks/assets/useAllAssets'
import useBorrowMarketAssetsTableData from 'hooks/useBorrowMarketAssetsTableData'
import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
import useLendingMarketAssetsTableData from 'hooks/useLendingMarketAssetsTableData'
import usePrices from 'hooks/usePrices'
import useStore from 'store'
import { BNCoin } from 'types/classes/BNCoin'

View File

@ -8,6 +8,7 @@ import AccountDetailsLeverage from 'components/account/AccountDetails/AccountDet
import Skeleton from 'components/account/AccountDetails/Skeleton'
import AccountPerpPositionTable from 'components/account/AccountPerpPositionTable'
import { HealthGauge } from 'components/account/Health/HealthGauge'
import useBorrowMarketAssetsTableData from 'components/borrow/Table/useBorrowMarketAssetsTableData'
import EscButton from 'components/common/Button/EscButton'
import { glowElement } from 'components/common/Button/utils'
import Card from 'components/common/Card'
@ -15,6 +16,7 @@ import DisplayCurrency from 'components/common/DisplayCurrency'
import { FormattedNumber } from 'components/common/FormattedNumber'
import { ThreeDots } from 'components/common/Icons'
import Text from 'components/common/Text'
import useLendingMarketAssetsTableData from 'components/earn/lend/Table/useLendingMarketAssetsTableData'
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
import { LocalStorageKeys } from 'constants/localStorageKeys'
import { ORACLE_DENOM } from 'constants/oracle'
@ -24,10 +26,8 @@ import useCurrentAccount from 'hooks/accounts/useCurrentAccount'
import useAllAssets from 'hooks/assets/useAllAssets'
import useLocalStorage from 'hooks/localStorage/useLocalStorage'
import useAccountId from 'hooks/useAccountId'
import useBorrowMarketAssetsTableData from 'hooks/useBorrowMarketAssetsTableData'
import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
import useHealthComputer from 'hooks/useHealthComputer'
import useLendingMarketAssetsTableData from 'hooks/useLendingMarketAssetsTableData'
import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
import usePrices from 'hooks/usePrices'
import useStore from 'store'
import { BNCoin } from 'types/classes/BNCoin'

View File

@ -10,7 +10,7 @@ import Text from 'components/common/Text'
import WalletBridges from 'components/Wallet/WalletBridges'
import { BN_ZERO } from 'constants/math'
import useBaseAsset from 'hooks/assets/useBasetAsset'
import useMarketAssets from 'hooks/markets/useMarketAssets'
import useMarkets from 'hooks/markets/useMarkets'
import useAutoLend from 'hooks/useAutoLend'
import { useUpdatedAccount } from 'hooks/useUpdatedAccount'
import useWalletBalances from 'hooks/useWalletBalances'
@ -35,7 +35,8 @@ export default function AccountFundContent(props: Props) {
const { autoLendEnabledAccountIds } = useAutoLend()
const isLending = autoLendEnabledAccountIds.includes(props.accountId)
const [fundingAssets, setFundingAssets] = useState<BNCoin[]>([])
const { data: marketAssets } = useMarketAssets()
const markets = useMarkets()
const { data: walletBalances } = useWalletBalances(props.address)
const { simulateDeposits } = useUpdatedAccount(props.account)
const baseAsset = useBaseAsset()
@ -127,7 +128,7 @@ export default function AccountFundContent(props: Props) {
const depositCapReachedCoins = useMemo(() => {
const depositCapReachedCoins: BNCoin[] = []
fundingAssets.forEach((asset) => {
const marketAsset = marketAssets.find(byDenom(asset.denom))
const marketAsset = markets.find(byDenom(asset.denom))
if (!marketAsset) return
const capLeft = getCapLeftWithBuffer(marketAsset.cap)
@ -137,7 +138,7 @@ export default function AccountFundContent(props: Props) {
depositCapReachedCoins.push(BNCoin.fromDenomAndBigNumber(asset.denom, capLeft))
})
return depositCapReachedCoins
}, [fundingAssets, marketAssets])
}, [fundingAssets, markets])
return (
<>

View File

@ -2,15 +2,15 @@ import { useCallback, useMemo } from 'react'
import AccountFundFullPage from 'components/account/AccountFund/AccountFundFullPage'
import Skeleton from 'components/account/AccountList/Skeleton'
import useBorrowMarketAssetsTableData from 'components/borrow/Table/useBorrowMarketAssetsTableData'
import Button from 'components/common/Button'
import { ArrowDownLine, ArrowUpLine, TrashBin } from 'components/common/Icons'
import SwitchAutoLend from 'components/common/Switch/SwitchAutoLend'
import useLendingMarketAssetsTableData from 'components/earn/lend/Table/useLendingMarketAssetsTableData'
import useAccount from 'hooks/accounts/useAccount'
import useAllAssets from 'hooks/assets/useAllAssets'
import useBorrowMarketAssetsTableData from 'hooks/useBorrowMarketAssetsTableData'
import useHealthComputer from 'hooks/useHealthComputer'
import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
import useLendingMarketAssetsTableData from 'hooks/useLendingMarketAssetsTableData'
import usePrices from 'hooks/usePrices'
import useStore from 'store'
import { calculateAccountApr, calculateAccountBalanceValue } from 'utils/accounts'

View File

@ -5,21 +5,21 @@ import AccountBalancesTable from 'components/account/AccountBalancesTable'
import AccountComposition from 'components/account/AccountComposition'
import AccountPerpPositionTable from 'components/account/AccountPerpPositionTable'
import HealthBar from 'components/account/Health/HealthBar'
import useBorrowMarketAssetsTableData from 'components/borrow/Table/useBorrowMarketAssetsTableData'
import Accordion from 'components/common/Accordion'
import Card from 'components/common/Card'
import DisplayCurrency from 'components/common/DisplayCurrency'
import { FormattedNumber } from 'components/common/FormattedNumber'
import { ArrowRight } from 'components/common/Icons'
import Text from 'components/common/Text'
import useLendingMarketAssetsTableData from 'components/earn/lend/Table/useLendingMarketAssetsTableData'
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
import { LocalStorageKeys } from 'constants/localStorageKeys'
import { BN_ZERO } from 'constants/math'
import { ORACLE_DENOM } from 'constants/oracle'
import useAllAssets from 'hooks/assets/useAllAssets'
import useLocalStorage from 'hooks/localStorage/useLocalStorage'
import useBorrowMarketAssetsTableData from 'hooks/useBorrowMarketAssetsTableData'
import useHealthComputer from 'hooks/useHealthComputer'
import useLendingMarketAssetsTableData from 'hooks/useLendingMarketAssetsTableData'
import usePrices from 'hooks/usePrices'
import useStore from 'store'
import { BNCoin } from 'types/classes/BNCoin'

View File

@ -1,8 +1,8 @@
import AvailableBorrowingsTable from 'components/borrow/Table/AvailableBorrowingsTable'
import DepositedBorrowingsTable from 'components/borrow/Table/DepositedBorrowingsTable'
import useBorrowMarketAssetsTableData from 'components/borrow/Table/useBorrowMarketAssetsTableData'
import { BN_ZERO } from 'constants/math'
import useBorrowEnabledAssets from 'hooks/assets/useBorrowEnabledAssets'
import useBorrowMarketAssetsTableData from 'hooks/useBorrowMarketAssetsTableData'
export default function Borrowings() {
const data = useBorrowMarketAssetsTableData()
@ -30,10 +30,18 @@ function Fallback() {
max: 0,
liq: 0,
},
liquidity: null,
marketDepositAmount: BN_ZERO,
liquidity: BN_ZERO,
marketLiquidityRate: 0,
marketLiquidityAmount: BN_ZERO,
cap: {
denom: asset.denom,
max: BN_ZERO,
used: BN_ZERO,
},
debt: BN_ZERO,
borrowEnabled: true,
depositEnabled: true,
deposits: BN_ZERO,
accountDebt: BN_ZERO,
}))
return <AvailableBorrowingsTable data={data} isLoading />

View File

@ -16,15 +16,9 @@ export const debtSortingFn = (
): number => {
const assetA = a.original.asset
const assetB = b.original.asset
if (!a.original.debt || !b.original.debt) return 0
const assetAPrice = (a.original.liquidity?.value ?? BN_ZERO).div(
a.original.liquidity?.amount ?? BN_ZERO,
)
const assetBPrice = (b.original.liquidity?.value ?? BN_ZERO).div(
b.original.liquidity?.amount ?? BN_ZERO,
)
const debtA = a.original.debt.times(assetAPrice).shiftedBy(-assetA.decimals)
const debtB = b.original.debt.times(assetBPrice).shiftedBy(-assetB.decimals)
if (!a.original.accountDebt || !b.original.accountDebt) return 0
const debtA = a.original.accountDebt.shiftedBy(-assetA.decimals)
const debtB = b.original.accountDebt.shiftedBy(-assetB.decimals)
return debtA.minus(debtB).toNumber()
}
@ -38,5 +32,5 @@ export default function Debt(props: Props) {
if (!asset) return null
return <AmountAndValue asset={asset} amount={props.data?.debt ?? BN_ZERO} />
return <AmountAndValue asset={asset} amount={props.data?.accountDebt ?? BN_ZERO} />
}

View File

@ -19,8 +19,8 @@ export const liquiditySortingFn = (
): number => {
const assetA = a.original.asset
const assetB = b.original.asset
const liquidityA = demagnify(a.original.liquidity?.amount ?? 0, assetA)
const liquidityB = demagnify(b.original.liquidity?.amount ?? 0, assetB)
const liquidityA = demagnify(a.original.liquidity ?? 0, assetA)
const liquidityB = demagnify(b.original.liquidity ?? 0, assetB)
return liquidityA - liquidityB
}
@ -35,9 +35,9 @@ export default function Liquidity(props: Props) {
if (!asset) return null
if (liquidity === null) {
if (liquidity.isZero()) {
return <Loading />
}
return <AmountAndValue asset={asset} amount={liquidity.amount ?? BN_ZERO} />
return <AmountAndValue asset={asset} amount={liquidity ?? BN_ZERO} />
}

View File

@ -0,0 +1,38 @@
import { useMemo } from 'react'
import useCurrentAccount from 'hooks/accounts/useCurrentAccount'
import useMarkets from 'hooks/markets/useMarkets'
export default function useBorrowMarketAssetsTableData() {
const account = useCurrentAccount()
const markets = useMarkets()
return useMemo((): {
accountBorrowedAssets: BorrowMarketTableData[]
availableAssets: BorrowMarketTableData[]
allAssets: BorrowMarketTableData[]
} => {
const accountBorrowedAssets: BorrowMarketTableData[] = [],
availableAssets: BorrowMarketTableData[] = []
markets
.filter((market) => market.borrowEnabled)
.forEach((market) => {
const debt = account?.debts?.find((debt) => debt.denom === market.asset.denom)
const borrowMarketAsset: BorrowMarketTableData = {
...market,
accountDebt: debt?.amount,
}
;(borrowMarketAsset.accountDebt ? accountBorrowedAssets : availableAssets).push(
borrowMarketAsset,
)
})
return {
accountBorrowedAssets,
availableAssets,
allAssets: [...accountBorrowedAssets, ...availableAssets],
}
}, [account?.debts, markets])
}

View File

@ -2,28 +2,27 @@ import { FormattedNumber } from 'components/common/FormattedNumber'
import Text from 'components/common/Text'
interface Props {
availableLiquidity: BigNumber
asset: BorrowAsset
market: Market
}
export default function AvailableLiquidityMessage(props: Props) {
const { availableLiquidity, asset } = props
const { market } = props
return (
<div className='flex items-start p-4 bg-white/5'>
<div className='flex flex-col gap-2'>
<Text size='sm'>Not enough Liquidty!</Text>
<Text size='xs' className='text-white/40'>
{`This transaction would exceed the amount of ${asset.symbol} currently available for borrowing on Mars.`}
{`This transaction would exceed the amount of ${market.asset.symbol} currently available for borrowing on Mars.`}
</Text>
<div className='flex gap-1'>
<Text size='xs'>Available Liquidity:</Text>
<FormattedNumber
amount={availableLiquidity.toNumber()}
amount={market.liquidity.toNumber()}
options={{
abbreviated: true,
decimals: asset.decimals,
suffix: ` ${asset.symbol}`,
decimals: market.asset.decimals,
suffix: ` ${market.asset.symbol}`,
}}
className='text-xs text-white/60'
/>

View File

@ -23,9 +23,7 @@ export default function MarketDetails({ row, type }: Props) {
symbol: displayCurrencySymbol,
} = useDisplayCurrencyPrice()
const { asset, ltv, marketDepositAmount, marketLiquidityAmount } = row.original
const totalBorrowed = marketDepositAmount.minus(marketLiquidityAmount)
const { asset, ltv, cap, liquidity, deposits, debt } = row.original
const details: Detail[] = useMemo(() => {
const isDollar = displayCurrencySymbol === '$'
@ -33,7 +31,7 @@ export default function MarketDetails({ row, type }: Props) {
function getLendingMarketDetails() {
return [
{
amount: convertAmount(asset, marketDepositAmount).toNumber(),
amount: convertAmount(asset, deposits).toNumber(),
options: {
abbreviated: true,
suffix: isDollar ? undefined : ` ${displayCurrencySymbol}`,
@ -62,9 +60,7 @@ export default function MarketDetails({ row, type }: Props) {
title: 'Oracle Price',
},
{
amount: totalBorrowed.isZero()
? 0
: totalBorrowed.dividedBy(marketDepositAmount).multipliedBy(100).toNumber(),
amount: debt.isZero() ? 0 : debt.dividedBy(deposits).multipliedBy(100).toNumber(), // TODO: Check if this number is still correct
options: { minDecimals: 2, maxDecimals: 2, suffix: '%' },
title: 'Utilization Rate',
},
@ -74,7 +70,7 @@ export default function MarketDetails({ row, type }: Props) {
function getBorrowMarketDetails() {
return [
{
amount: convertAmount(asset, totalBorrowed).toNumber(),
amount: convertAmount(asset, debt).toNumber(),
options: {
abbreviated: true,
suffix: isDollar ? undefined : ` ${displayCurrencySymbol}`,
@ -93,9 +89,7 @@ export default function MarketDetails({ row, type }: Props) {
title: 'Oracle Price',
},
{
amount: totalBorrowed.isZero()
? 0
: totalBorrowed.dividedBy(marketDepositAmount).multipliedBy(100).toNumber(),
amount: debt.isZero() ? 0 : debt.dividedBy(deposits).multipliedBy(100).toNumber(), // TODO: CHeck if this is still correct
options: { minDecimals: 2, maxDecimals: 2, suffix: '%' },
title: 'Utilization Rate',
},
@ -105,14 +99,15 @@ export default function MarketDetails({ row, type }: Props) {
if (type === 'lend') return getLendingMarketDetails()
return getBorrowMarketDetails()
}, [
type,
asset,
marketDepositAmount,
ltv,
totalBorrowed,
displayCurrencySymbol,
type,
convertAmount,
asset,
debt,
ltv.max,
ltv.liq,
getConversionRate,
deposits,
])
return (

View File

@ -7,7 +7,7 @@ import { ChevronDown, ChevronRight } from 'components/common/Icons'
import Text from 'components/common/Text'
import { BN_ZERO } from 'constants/math'
import useAsset from 'hooks/assets/useAsset'
import useMarketAssets from 'hooks/markets/useMarketAssets'
import useMarkets from 'hooks/markets/useMarkets'
import { BNCoin } from 'types/classes/BNCoin'
import { byDenom } from 'utils/array'
import { formatValue } from 'utils/formatters'
@ -22,7 +22,8 @@ interface Props extends SelectOption {
export default function Option(props: Props) {
const isCoin = !!props.denom
const { data: marketAssets } = useMarketAssets()
const markets = useMarkets()
const asset = useAsset(props.denom || '')
function handleOnClick(value: string | undefined) {
@ -32,7 +33,7 @@ export default function Option(props: Props) {
if (isCoin) {
const balance = props.amount ?? BN_ZERO
const marketAsset = marketAssets.find(byDenom(props.denom || ''))
const marketAsset = markets.find(byDenom(props.denom || ''))
if (!asset || !marketAsset) return null

View File

@ -1,8 +1,8 @@
import AvailableLendsTable from 'components/earn/lend/Table/AvailableLendsTable'
import DepositedLendsTable from 'components/earn/lend/Table/DepositedLendsTable'
import useLendingMarketAssetsTableData from 'components/earn/lend/Table/useLendingMarketAssetsTableData'
import { BN_ZERO } from 'constants/math'
import useLendEnabledAssets from 'hooks/assets/useLendEnabledAssets'
import useLendingMarketAssetsTableData from 'hooks/useLendingMarketAssetsTableData'
export default function Lends() {
const { accountLentAssets, availableAssets, allAssets } = useLendingMarketAssetsTableData()
@ -23,10 +23,11 @@ function Fallback() {
const data: LendingMarketTableData[] = assets.map((asset) => ({
asset,
marketDepositCap: BN_ZERO,
borrowEnabled: false,
marketDepositAmount: BN_ZERO,
marketLiquidityAmount: BN_ZERO,
borrowEnabled: true,
depositEnabled: true,
debt: BN_ZERO,
deposits: BN_ZERO,
liquidity: BN_ZERO,
cap: {
max: BN_ZERO,
used: BN_ZERO,

View File

@ -1,50 +1,35 @@
import { useMemo } from 'react'
import { BN_ZERO } from 'constants/math'
import useAllAssets from 'hooks/assets/useAllAssets'
import useMarketDeposits from 'hooks/markets/useMarketDeposits'
import useMarketLiquidities from 'hooks/markets/useMarketLiquidities'
import useMarkets from 'hooks/markets/useMarkets'
import useCurrentAccountLends from 'hooks/useCurrentAccountLends'
import useDepositEnabledMarkets from 'hooks/useDepositEnabledMarkets'
import useDisplayCurrencyPrice from 'hooks/useDisplayCurrencyPrice'
import { byDenom } from 'utils/array'
import { BN } from 'utils/helpers'
function useLendingMarketAssetsTableData(): {
accountLentAssets: LendingMarketTableData[]
availableAssets: LendingMarketTableData[]
allAssets: LendingMarketTableData[]
} {
const markets = useDepositEnabledMarkets()
const markets = useMarkets()
const accountLentAmounts = useCurrentAccountLends()
const { data: marketLiquidities } = useMarketLiquidities()
const { data: marketDeposits } = useMarketDeposits()
const { convertAmount } = useDisplayCurrencyPrice()
const assets = useAllAssets()
return useMemo(() => {
const accountLentAssets: LendingMarketTableData[] = [],
availableAssets: LendingMarketTableData[] = []
markets.forEach(({ denom, cap, ltv, apy, borrowEnabled }) => {
const asset = assets.find(byDenom(denom)) as Asset
const marketDepositAmount = BN(marketDeposits.find(byDenom(denom))?.amount ?? 0)
const marketLiquidityAmount = BN(marketLiquidities.find(byDenom(denom))?.amount ?? 0)
const accountLentAmount = accountLentAmounts.find(byDenom(denom))?.amount ?? BN_ZERO
markets.forEach((market) => {
const accountLentAmount =
accountLentAmounts.find(byDenom(market.asset.denom))?.amount ?? BN_ZERO
const accountLentValue = accountLentAmount
? convertAmount(asset, accountLentAmount)
? convertAmount(market.asset, accountLentAmount)
: undefined
const lendingMarketAsset: LendingMarketTableData = {
asset,
marketDepositAmount,
...market,
accountLentValue,
accountLentAmount,
marketLiquidityAmount,
apy,
ltv,
borrowEnabled,
cap,
}
if (lendingMarketAsset.accountLentAmount?.isZero()) {
@ -59,7 +44,7 @@ function useLendingMarketAssetsTableData(): {
availableAssets,
allAssets: [...accountLentAssets, ...availableAssets],
}
}, [markets, assets, marketDeposits, marketLiquidities, accountLentAmounts, convertAmount])
}, [markets, accountLentAmounts, convertAmount])
}
export default useLendingMarketAssetsTableData

View File

@ -2,7 +2,7 @@ import React from 'react'
import { FormattedNumber } from 'components/common/FormattedNumber'
import Loading from 'components/common/Loading'
import useMarketBorrowings from 'hooks/markets/useMarketBorrowings'
import useMarket from 'hooks/markets/useMarket'
export const APY_META = { accessorKey: 'apy', header: 'APY Range' }
@ -12,10 +12,7 @@ interface Props {
export default function Apy(props: Props) {
const { vault } = props
const { data: marketBorrowings } = useMarketBorrowings()
const borrowRate = marketBorrowings.find((asset) => asset.denom === vault.hls?.borrowDenom)
?.borrowRate
const borrowRate = useMarket(vault.hls?.borrowDenom || '')?.apy.borrow
if (vault.apy === null || borrowRate === null) return <Loading />

View File

@ -5,7 +5,7 @@ import { FormattedNumber } from 'components/common/FormattedNumber'
import Loading from 'components/common/Loading'
import TitleAndSubCell from 'components/common/TitleAndSubCell'
import useAllAssets from 'hooks/assets/useAllAssets'
import useBorrowAsset from 'hooks/useBorrowAsset'
import useMarket from 'hooks/markets/useMarket'
import usePrices from 'hooks/usePrices'
import { calculateAccountLeverage } from 'utils/accounts'
import { getLeveragedApy } from 'utils/math'
@ -27,7 +27,7 @@ interface Props {
export default function ActiveAPY(props: Props) {
const { data: prices } = usePrices()
const assets = useAllAssets()
const borrowRate = useBorrowAsset(props.account.strategy.denoms.borrow)?.borrowRate
const borrowRate = useMarket(props.account.strategy.denoms.borrow)?.apy.borrow
const leverage = useMemo(
() => calculateAccountLeverage(props.account, prices, assets),

View File

@ -3,7 +3,7 @@ import { Row } from '@tanstack/react-table'
import { FormattedNumber } from 'components/common/FormattedNumber'
import Loading from 'components/common/Loading'
import TitleAndSubCell from 'components/common/TitleAndSubCell'
import useBorrowAsset from 'hooks/useBorrowAsset'
import useMarket from 'hooks/markets/useMarket'
import { getLeveragedApy } from 'utils/math'
export const APY_RANGE_META = { header: 'APY range', accessorKey: 'apy' }
@ -19,7 +19,7 @@ interface Props {
export default function ApyRange(props: Props) {
const baseApy = props.strategy.apy
const borrowRate = useBorrowAsset(props.strategy.denoms.borrow)?.borrowRate
const borrowRate = useMarket(props.strategy.denoms.borrow)?.apy.borrow
if (!borrowRate || props.isLoading || !baseApy) {
return <Loading />

View File

@ -1,12 +1,12 @@
import React, { Suspense, useMemo } from 'react'
import AccountBalancesTable from 'components/account/AccountBalancesTable'
import useBorrowMarketAssetsTableData from 'components/borrow/Table/useBorrowMarketAssetsTableData'
import Card from 'components/common/Card'
import TableSkeleton from 'components/common/Table/TableSkeleton'
import Text from 'components/common/Text'
import useLendingMarketAssetsTableData from 'components/earn/lend/Table/useLendingMarketAssetsTableData'
import useAccount from 'hooks/accounts/useAccount'
import useBorrowMarketAssetsTableData from 'hooks/useBorrowMarketAssetsTableData'
import useLendingMarketAssetsTableData from 'hooks/useLendingMarketAssetsTableData'
interface Props {
accountId: string

View File

@ -1,15 +1,15 @@
import { Suspense, useMemo } from 'react'
import useBorrowMarketAssetsTableData from 'components/borrow/Table/useBorrowMarketAssetsTableData'
import DisplayCurrency from 'components/common/DisplayCurrency'
import { FormattedNumber } from 'components/common/FormattedNumber'
import useLendingMarketAssetsTableData from 'components/earn/lend/Table/useLendingMarketAssetsTableData'
import Skeleton from 'components/portfolio/SummarySkeleton'
import { MAX_AMOUNT_DECIMALS } from 'constants/math'
import useAccount from 'hooks/accounts/useAccount'
import useAllAssets from 'hooks/assets/useAllAssets'
import useBorrowMarketAssetsTableData from 'hooks/useBorrowMarketAssetsTableData'
import useHealthComputer from 'hooks/useHealthComputer'
import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
import useLendingMarketAssetsTableData from 'hooks/useLendingMarketAssetsTableData'
import usePrices from 'hooks/usePrices'
import { getAccountSummaryStats } from 'utils/accounts'
import { DEFAULT_PORTFOLIO_STATS } from 'utils/constants'

View File

@ -2,8 +2,10 @@ import classNames from 'classnames'
import { ReactNode, useMemo } from 'react'
import { NavLink, useParams, useSearchParams } from 'react-router-dom'
import useBorrowMarketAssetsTableData from 'components/borrow/Table/useBorrowMarketAssetsTableData'
import { FormattedNumber } from 'components/common/FormattedNumber'
import Loading from 'components/common/Loading'
import useLendingMarketAssetsTableData from 'components/earn/lend/Table/useLendingMarketAssetsTableData'
import Skeleton from 'components/portfolio/Card/Skeleton'
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
import { LocalStorageKeys } from 'constants/localStorageKeys'
@ -12,10 +14,8 @@ import useAccount from 'hooks/accounts/useAccount'
import useAllAssets from 'hooks/assets/useAllAssets'
import useLocalStorage from 'hooks/localStorage/useLocalStorage'
import useAccountId from 'hooks/useAccountId'
import useBorrowMarketAssetsTableData from 'hooks/useBorrowMarketAssetsTableData'
import useHealthComputer from 'hooks/useHealthComputer'
import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
import useLendingMarketAssetsTableData from 'hooks/useLendingMarketAssetsTableData'
import usePrices from 'hooks/usePrices'
import {
calculateAccountApr,

View File

@ -1,15 +1,15 @@
import { useMemo } from 'react'
import { useParams } from 'react-router-dom'
import useBorrowMarketAssetsTableData from 'components/borrow/Table/useBorrowMarketAssetsTableData'
import DisplayCurrency from 'components/common/DisplayCurrency'
import { FormattedNumber } from 'components/common/FormattedNumber'
import useLendingMarketAssetsTableData from 'components/earn/lend/Table/useLendingMarketAssetsTableData'
import SummarySkeleton from 'components/portfolio/SummarySkeleton'
import { MAX_AMOUNT_DECIMALS } from 'constants/math'
import useAccounts from 'hooks/accounts/useAccounts'
import useAllAssets from 'hooks/assets/useAllAssets'
import useBorrowMarketAssetsTableData from 'hooks/useBorrowMarketAssetsTableData'
import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
import useLendingMarketAssetsTableData from 'hooks/useLendingMarketAssetsTableData'
import usePrices from 'hooks/usePrices'
import useStore from 'store'
import { getAccountSummaryStats } from 'utils/accounts'

View File

@ -1,9 +1,9 @@
import { useMemo } from 'react'
import AccountBalancesTable from 'components/account/AccountBalancesTable'
import useBorrowMarketAssetsTableData from 'components/borrow/Table/useBorrowMarketAssetsTableData'
import useLendingMarketAssetsTableData from 'components/earn/lend/Table/useLendingMarketAssetsTableData'
import useCurrentAccount from 'hooks/accounts/useCurrentAccount'
import useBorrowMarketAssetsTableData from 'hooks/useBorrowMarketAssetsTableData'
import useLendingMarketAssetsTableData from 'hooks/useLendingMarketAssetsTableData'
export default function AccountDetailsCard() {
const account = useCurrentAccount()

View File

@ -6,8 +6,7 @@ import Text from 'components/common/Text'
import AssetSelectorItem from 'components/trade/TradeModule/AssetSelector/AssetSelectorItem'
import useCurrentAccount from 'hooks/accounts/useCurrentAccount'
import useMarketEnabledAssets from 'hooks/assets/useMarketEnabledAssets'
import useMarketAssets from 'hooks/markets/useMarketAssets'
import useMarketDeposits from 'hooks/markets/useMarketDeposits'
import useMarkets from 'hooks/markets/useMarkets'
import usePrices from 'hooks/usePrices'
import useStore from 'store'
import { getMergedBalancesForAsset } from 'utils/accounts'
@ -26,8 +25,7 @@ export default function AssetList(props: Props) {
const baseDenom = useStore((s) => s.chainConfig.assets[0].denom)
const { assets, type, isOpen, toggleOpen, onChangeAsset } = props
const account = useCurrentAccount()
const { data: marketAssets } = useMarketAssets()
const { data: marketDeposits } = useMarketDeposits()
const markets = useMarkets()
const { data: prices } = usePrices()
const marketEnabledAssets = useMarketEnabledAssets()
const balances = useMemo(() => {
@ -36,8 +34,8 @@ export default function AssetList(props: Props) {
}, [account, marketEnabledAssets])
const sortedAssets = useMemo(
() => sortAssetsOrPairs(assets, prices, marketDeposits, balances, baseDenom) as Asset[],
[assets, prices, marketDeposits, balances, baseDenom],
() => sortAssetsOrPairs(assets, prices, markets, balances, baseDenom) as Asset[],
[assets, prices, markets, balances, baseDenom],
)
return (
@ -63,9 +61,7 @@ export default function AssetList(props: Props) {
balances={balances}
key={`${type}-${asset.symbol}`}
onSelect={props.onChangeAsset}
depositCap={
type === 'buy' ? marketAssets?.find(byDenom(asset.denom))?.cap : undefined
}
depositCap={type === 'buy' ? markets?.find(byDenom(asset.denom))?.cap : undefined}
asset={asset}
/>
))}

View File

@ -5,8 +5,7 @@ import AssetSelectorItem from 'components/trade/TradeModule/AssetSelector/AssetS
import useCurrentAccount from 'hooks/accounts/useCurrentAccount'
import useBaseAsset from 'hooks/assets/useBasetAsset'
import useMarketEnabledAssets from 'hooks/assets/useMarketEnabledAssets'
import useMarketAssets from 'hooks/markets/useMarketAssets'
import useMarketDeposits from 'hooks/markets/useMarketDeposits'
import useMarkets from 'hooks/markets/useMarkets'
import usePrices from 'hooks/usePrices'
import { getMergedBalancesForAsset } from 'utils/accounts'
import { byDenom } from 'utils/array'
@ -22,8 +21,7 @@ interface Props {
export default function PairsList(props: Props) {
const account = useCurrentAccount()
const { data: marketAssets } = useMarketAssets()
const { data: marketDeposits } = useMarketDeposits()
const markets = useMarkets()
const { data: prices } = usePrices()
const baseDenom = useBaseAsset().denom
const marketEnabledAssets = useMarketEnabledAssets()
@ -44,8 +42,8 @@ export default function PairsList(props: Props) {
}, [props.stables, props.assets])
const sortedPairs = useMemo(
() => sortAssetsOrPairs(pairs, prices, marketDeposits, balances, baseDenom) as AssetPair[],
[pairs, prices, marketDeposits, balances, baseDenom],
() => sortAssetsOrPairs(pairs, prices, markets, balances, baseDenom) as AssetPair[],
[pairs, prices, markets, balances, baseDenom],
)
return (
@ -62,7 +60,7 @@ export default function PairsList(props: Props) {
balances={balances}
key={`${assetPair.buy.symbol}-${assetPair.sell.symbol}`}
onSelect={props.onChangeAssetPair}
depositCap={marketAssets?.find(byDenom(assetPair.buy.denom))?.cap}
depositCap={markets?.find(byDenom(assetPair.buy.denom))?.cap}
asset={assetPair.buy}
sellAsset={assetPair.sell}
/>

View File

@ -22,8 +22,7 @@ import { BN_ZERO } from 'constants/math'
import useCurrentAccount from 'hooks/accounts/useCurrentAccount'
import useMarketEnabledAssets from 'hooks/assets/useMarketEnabledAssets'
import useLocalStorage from 'hooks/localStorage/useLocalStorage'
import useMarketAssets from 'hooks/markets/useMarketAssets'
import useMarketBorrowings from 'hooks/markets/useMarketBorrowings'
import useMarkets from 'hooks/markets/useMarkets'
import useAutoLend from 'hooks/useAutoLend'
import useChainConfig from 'hooks/useChainConfig'
import useHealthComputer from 'hooks/useHealthComputer'
@ -53,8 +52,7 @@ export default function SwapForm(props: Props) {
const [slippage] = useLocalStorage(LocalStorageKeys.SLIPPAGE, DEFAULT_SETTINGS.slippage)
const { computeMaxSwapAmount } = useHealthComputer(account)
const [tradeDirection, setTradeDirection] = useState<TradeDirection>('long')
const { data: borrowAssets } = useMarketBorrowings()
const { data: marketAssets } = useMarketAssets()
const markets = useMarkets()
const [inputAsset, outputAsset] = useMemo(() => {
if (isAdvanced) return [sellAsset, buyAsset]
@ -65,7 +63,7 @@ export default function SwapForm(props: Props) {
inputAsset.denom,
outputAsset.denom,
)
const isBorrowEnabled = !!marketAssets.find(byDenom(inputAsset.denom))?.borrowEnabled
const isBorrowEnabled = !!markets.find(byDenom(inputAsset.denom))?.borrowEnabled
const isRepayable = !!account?.debts.find(byDenom(outputAsset.denom))
const [isMarginChecked, setMarginChecked] = useToggle(isBorrowEnabled ? useMargin : false)
const [isAutoRepayChecked, setAutoRepayChecked] = useToggle(
@ -87,7 +85,7 @@ export default function SwapForm(props: Props) {
const assets = useMarketEnabledAssets()
const depositCapReachedCoins: BNCoin[] = useMemo(() => {
const outputMarketAsset = marketAssets.find(byDenom(outputAsset.denom))
const outputMarketAsset = markets.find(byDenom(outputAsset.denom))
if (!outputMarketAsset) return []
@ -97,7 +95,7 @@ export default function SwapForm(props: Props) {
}
return []
}, [marketAssets, outputAsset.denom, outputAssetAmount])
}, [markets, outputAsset.denom, outputAssetAmount])
const onChangeInputAmount = useCallback(
(amount: BigNumber) => {
@ -305,9 +303,9 @@ export default function SwapForm(props: Props) {
modal,
])
const borrowAsset = useMemo(
() => borrowAssets.find(byDenom(inputAsset.denom)),
[borrowAssets, inputAsset.denom],
const borrowMarket = useMemo(
() => markets.find((market) => market.asset.denom === inputAsset.denom),
[markets, inputAsset.denom],
)
useEffect(() => {
@ -324,8 +322,8 @@ export default function SwapForm(props: Props) {
)
const availableLiquidity = useMemo(
() => borrowAsset?.liquidity?.amount ?? BN_ZERO,
[borrowAsset?.liquidity?.amount],
() => borrowMarket?.liquidity ?? BN_ZERO,
[borrowMarket?.liquidity],
)
const isSwapDisabled = useMemo(
@ -349,7 +347,7 @@ export default function SwapForm(props: Props) {
<MarginToggle
checked={isMarginChecked}
onChange={handleMarginToggleChange}
disabled={!borrowAsset?.isMarket}
disabled={!borrowMarket?.borrowEnabled}
borrowAssetSymbol={inputAsset.symbol}
/>
<Divider />
@ -411,11 +409,8 @@ export default function SwapForm(props: Props) {
className='p-4 bg-white/5'
/>
{borrowAsset && borrowAmount.isGreaterThanOrEqualTo(availableLiquidity) && (
<AvailableLiquidityMessage
availableLiquidity={borrowAsset?.liquidity?.amount ?? BN_ZERO}
asset={borrowAsset}
/>
{borrowMarket && borrowAmount.isGreaterThanOrEqualTo(availableLiquidity) && (
<AvailableLiquidityMessage market={borrowMarket} />
)}
{isAdvanced ? (
<AssetAmountInput
@ -450,7 +445,7 @@ export default function SwapForm(props: Props) {
<TradeSummary
sellAsset={inputAsset}
buyAsset={outputAsset}
borrowRate={borrowAsset?.borrowRate}
borrowRate={borrowMarket?.apy.borrow}
buyAction={handleBuyClick}
buyButtonDisabled={isSwapDisabled}
showProgressIndicator={isConfirming || isRouteLoading}

View File

@ -6,7 +6,8 @@ import useChainConfig from 'hooks/useChainConfig'
export default function useAccountIdsAndKinds(address?: string, suspense = true, noHls = false) {
const chainConfig = useChainConfig()
return useSWR(
`chains/${chainConfig.id}/wallets/${address}/account-ids${noHls && '-without-hls'}`,
address &&
`chains/${chainConfig.id}/wallets/${address}/account-ids${noHls ? '-without-hls' : ''}`,
() =>
getAccountIds(chainConfig, address).then((accountIdsAndKinds) => {
if (noHls) {

View File

@ -8,7 +8,7 @@ export default function useAccounts(kind: AccountKind, address?: string, suspens
const chainConfig = useChainConfig()
return useSWR(
`chains/${chainConfig.id}/accounts/${kind}`,
address && `chains/${chainConfig.id}/accounts/${kind}`,
() => getAccounts(kind, chainConfig, address),
{
suspense: suspense,

View File

@ -0,0 +1,9 @@
import { useMemo } from 'react'
import useMarkets from 'hooks/markets/useMarkets'
export default function useMarket(denom: string) {
const markets = useMarkets()
return useMemo(() => markets.find((market) => market.asset.denom === denom), [denom, markets])
}

View File

@ -1,14 +0,0 @@
import useSWR from 'swr'
import getMarkets from 'api/markets/getMarkets'
import useChainConfig from 'hooks/useChainConfig'
export default function useMarketAssets() {
const chainConfig = useChainConfig()
return useSWR(`chains/${chainConfig.id}/markets`, () => getMarkets(chainConfig), {
suspense: true,
fallbackData: [],
revalidateOnFocus: false,
keepPreviousData: false,
})
}

View File

@ -1,17 +0,0 @@
import useSWR from 'swr'
import getMarketBorrowings from 'api/markets/getMarketBorrowings'
import useChainConfig from 'hooks/useChainConfig'
export default function useMarketBorrowings() {
const chainConfig = useChainConfig()
return useSWR(
`chains/${chainConfig.id}/markets/borrowings`,
() => getMarketBorrowings(chainConfig),
{
fallbackData: [],
suspense: false,
revalidateOnFocus: false,
},
)
}

View File

@ -0,0 +1,26 @@
import useSWR from 'swr'
import useMarketEnabledAssets from 'hooks/assets/useMarketEnabledAssets'
import useChainConfig from 'hooks/useChainConfig'
import useClients from 'hooks/useClients'
export default function useMarketDepositCaps() {
const chainConfig = useChainConfig()
const clients = useClients()
const assets = useMarketEnabledAssets()
return useSWR(
assets.length > 0 && clients && `chains/${chainConfig.id}/markets/depositCap`,
() => getMarketsDepositCap(clients!, assets),
{
revalidateOnFocus: false,
revalidateOnReconnect: false,
revalidateIfStale: false,
},
)
}
async function getMarketsDepositCap(clients: ContractClients, assets: Asset[]) {
const capQueries = assets.map((asset) => clients.params.totalDeposit({ denom: asset.denom }))
return Promise.all(capQueries)
}

View File

@ -1,13 +0,0 @@
import useSWR from 'swr'
import getMarketDeposits from 'api/markets/getMarketDeposits'
import useChainConfig from 'hooks/useChainConfig'
export default function useMarketDeposits() {
const chainConfig = useChainConfig()
return useSWR(`chains/${chainConfig.id}/markets/deposits`, () => getMarketDeposits(chainConfig), {
suspense: true,
fallbackData: [],
revalidateOnFocus: false,
})
}

View File

@ -1,17 +0,0 @@
import useSWR from 'swr'
import getMarketLiquidities from 'api/markets/getMarketLiquidities'
import useChainConfig from 'hooks/useChainConfig'
export default function useMarketLiquidities() {
const chainConfig = useChainConfig()
return useSWR(
`chains/${chainConfig.id}/markets/liquidities`,
() => getMarketLiquidities(chainConfig),
{
suspense: true,
fallbackData: [],
revalidateOnFocus: false,
},
)
}

View File

@ -0,0 +1,42 @@
import useSWR from 'swr'
import useMarketDepositCaps from 'hooks/markets/useMarketDepositCaps'
import useMarketsInfo from 'hooks/markets/useMarketsInfo'
import useAssetParams from 'hooks/params/useAssetParams'
import useAssets from 'hooks/useAssets'
import useChainConfig from 'hooks/useChainConfig'
import {
AssetParamsBaseForAddr as AssetParams,
TotalDepositResponse,
} from 'types/generated/mars-params/MarsParams.types'
import { Market as RedBankMarket } from 'types/generated/mars-red-bank/MarsRedBank.types'
import { byDenom } from 'utils/array'
import { resolveMarketResponse } from 'utils/resolvers'
export default function useMarkets() {
const chainConfig = useChainConfig()
const { data: marketInfos } = useMarketsInfo()
const { data: marketDepositCaps } = useMarketDepositCaps()
const { data: assetParams } = useAssetParams()
const assets = useAssets()
return useSWR(
!!marketInfos?.length &&
!!marketDepositCaps?.length &&
!!assetParams.length &&
`chains/${chainConfig.id}/markets`,
() => {
return assets.map((asset) =>
resolveMarketResponse(
asset,
marketInfos!.find(byDenom(asset.denom)) as RedBankMarket & Partial<Market>,
assetParams.find(byDenom(asset.denom)) as AssetParams,
marketDepositCaps!.find(byDenom(asset.denom)) as TotalDepositResponse,
),
)
},
{
fallbackData: [],
},
).data
}

View File

@ -0,0 +1,47 @@
import useSWR from 'swr'
import useChainConfig from 'hooks/useChainConfig'
import useClients from 'hooks/useClients'
import { BN } from 'utils/helpers'
import iterateContractQuery from 'utils/iterateContractQuery'
export default function useMarketsInfo() {
const chainConfig = useChainConfig()
const clients = useClients()
return useSWR(
clients && `chains/${chainConfig.id}/markets/info`,
() => getMarketsInfo(clients!),
{
revalidateOnFocus: false,
revalidateOnReconnect: false,
revalidateIfStale: false,
},
)
}
async function getMarketsInfo(clients: ContractClients) {
const markets = await iterateContractQuery(clients.redBank.markets)
const debts$ = markets.map((market) =>
clients.redBank.underlyingDebtAmount({
denom: market.denom,
amountScaled: market.debt_total_scaled,
}),
)
const liquidities$ = markets.map((market) =>
clients.redBank.underlyingLiquidityAmount({
denom: market.denom,
amountScaled: market.collateral_total_scaled,
}),
)
const [debts, liquidity] = await Promise.all([Promise.all(debts$), Promise.all(liquidities$)])
return markets.map((market, index) => ({
...market,
debt: BN(debts[index]),
deposits: BN(liquidity[index]),
liquidity: BN(liquidity[index]).minus(debts[index]),
}))
}

View File

@ -1,15 +1,45 @@
import useSWR from 'swr'
import calculateAssetIncentivesApy from 'api/incentives/calculateAssetIncentivesApy'
import getTotalActiveEmissionValue from 'api/incentives/getTotalActiveEmissionValue'
import useMarket from 'hooks/markets/useMarket'
import useChainConfig from 'hooks/useChainConfig'
import usePrice from 'hooks/usePrice'
import { SECONDS_IN_A_YEAR } from 'utils/constants'
import { BN } from 'utils/helpers'
export default function useAssetIncentivesApy(denom: string) {
const chainConfig = useChainConfig()
const market = useMarket(denom)
const price = usePrice(denom)
return useSWR(
`chains/${chainConfig.id}/assets/${denom}/incentives`,
() => calculateAssetIncentivesApy(chainConfig, denom),
market && `chains/${chainConfig.id}/assets/${denom}/incentives`,
() => calculateAssetIncentivesApy(chainConfig, market!, price),
{
revalidateOnFocus: false,
},
)
}
async function calculateAssetIncentivesApy(
chainConfig: ChainConfig,
market: Market,
price: BigNumber,
) {
const totalActiveEmissionValue = await getTotalActiveEmissionValue(
chainConfig,
market.asset.denom,
)
if (!totalActiveEmissionValue) return null
const marketLiquidityValue = BN(market.deposits)
.shiftedBy(-market.asset.decimals)
.multipliedBy(price)
const marketReturns = BN(market.apy.deposit).multipliedBy(marketLiquidityValue)
const annualEmission = totalActiveEmissionValue.multipliedBy(SECONDS_IN_A_YEAR)
const totalAnnualReturnsValue = annualEmission.plus(marketReturns)
return totalAnnualReturnsValue.dividedBy(marketLiquidityValue).multipliedBy(100)
}

View File

@ -1,10 +0,0 @@
import useMarketBorrowings from 'hooks/markets/useMarketBorrowings'
import { byDenom } from 'utils/array'
export default function useBorrowAsset(denom: string) {
const { data: borrowAssets } = useMarketBorrowings()
if (!borrowAssets.length) return null
return borrowAssets.find(byDenom(denom))
}

View File

@ -1,8 +0,0 @@
import { useMemo } from 'react'
import useMarketAssets from 'hooks/markets/useMarketAssets'
export default function useBorrowEnabledMarkets() {
const { data: markets } = useMarketAssets()
return useMemo(() => markets.filter((market) => market.borrowEnabled), [markets])
}

View File

@ -1,55 +0,0 @@
import { useMemo } from 'react'
import useCurrentAccount from 'hooks/accounts/useCurrentAccount'
import useAllAssets from 'hooks/assets/useAllAssets'
import useMarketBorrowings from 'hooks/markets/useMarketBorrowings'
import useMarketDeposits from 'hooks/markets/useMarketDeposits'
import useMarketLiquidities from 'hooks/markets/useMarketLiquidities'
import useBorrowEnabledMarkets from 'hooks/useBorrowEnabledMarkets'
import { byDenom } from 'utils/array'
import { BN } from 'utils/helpers'
export default function useBorrowMarketAssetsTableData() {
const markets = useBorrowEnabledMarkets()
const account = useCurrentAccount()
const { data: borrowData } = useMarketBorrowings()
const { data: marketDeposits } = useMarketDeposits()
const { data: marketLiquidities } = useMarketLiquidities()
const assets = useAllAssets()
return useMemo((): {
accountBorrowedAssets: BorrowMarketTableData[]
availableAssets: BorrowMarketTableData[]
allAssets: BorrowMarketTableData[]
} => {
const accountBorrowedAssets: BorrowMarketTableData[] = [],
availableAssets: BorrowMarketTableData[] = []
markets.forEach(({ denom, apy, ltv }) => {
const asset = assets.find(byDenom(denom)) as Asset
const borrow = borrowData.find((borrow) => borrow.denom === denom)
const marketDepositAmount = BN(marketDeposits.find(byDenom(denom))?.amount ?? 0)
const marketLiquidityAmount = BN(marketLiquidities.find(byDenom(denom))?.amount ?? 0)
const debt = account?.debts?.find((debt) => debt.denom === denom)
if (!borrow) return
const borrowMarketAsset: BorrowMarketTableData = {
...borrow,
asset,
debt: debt?.amount,
marketDepositAmount,
marketLiquidityAmount,
apy,
ltv,
}
;(borrowMarketAsset.debt ? accountBorrowedAssets : availableAssets).push(borrowMarketAsset)
})
return {
accountBorrowedAssets,
availableAssets,
allAssets: [...accountBorrowedAssets, ...availableAssets],
}
}, [account?.debts, assets, borrowData, marketDeposits, marketLiquidities, markets])
}

View File

@ -34,6 +34,9 @@ export default function useClients() {
} as ContractClients
},
{
revalidateOnFocus: false,
revalidateOnReconnect: false,
revalidateIfStale: false,
keepPreviousData: false,
},
)

View File

@ -1,6 +0,0 @@
import useMarketAssets from 'hooks/markets/useMarketAssets'
export default function useDepositEnabledMarkets() {
const { data: markets } = useMarketAssets()
return markets.filter((market) => market.depositEnabled)
}

View File

@ -5,8 +5,12 @@ import useChainConfig from 'hooks/useChainConfig'
export default function useHLSStakingAssets() {
const chainConfig = useChainConfig()
return useSWR('hls-staking', () => getHLSStakingAssets(chainConfig), {
fallbackData: [],
revalidateOnFocus: false,
})
return useSWR(
`chains/${chainConfig.id}/assets/hls/staking`,
() => getHLSStakingAssets(chainConfig),
{
fallbackData: [],
revalidateOnFocus: false,
},
)
}

View File

@ -1,9 +1,9 @@
import { useMemo } from 'react'
import useVaults from 'hooks/useVaults'
export default function useVault(address: string) {
const { data: vaults } = useVaults(false)
if (!vaults?.length) return null
return vaults.find((v) => v.address === address) ?? null
return useMemo(() => vaults?.find((v) => v.address === address) ?? null, [vaults, address])
}

View File

@ -6,8 +6,12 @@ import useChainConfig from 'hooks/useChainConfig'
export default function useVaults(suspense: boolean = true, address?: string) {
const chainConfig = useChainConfig()
return useSWR(`chains/${chainConfig.id}/vaults/${address}`, () => getVaults(chainConfig), {
suspense,
revalidateOnFocus: false,
})
return useSWR(
address && `chains/${chainConfig.id}/vaults/${address}`,
() => getVaults(chainConfig),
{
suspense,
revalidateOnFocus: false,
},
)
}

View File

@ -7,7 +7,7 @@ export default function useWalletBalances(address?: string) {
const chainConfig = useChainConfig()
return useSWR(
`chains/${chainConfig.id}/wallets/${address}/balances`,
address && `chains/${chainConfig.id}/wallets/${address}/balances`,
() => getWalletBalances(chainConfig, address || ''),
{
isPaused: () => !address,

View File

@ -2,19 +2,21 @@ import classNames from 'classnames'
import { Suspense } from 'react'
import { isMobile } from 'react-device-detect'
import { useLocation } from 'react-router-dom'
import { SWRConfig } from 'swr'
import AccountDetails from 'components/account/AccountDetails'
import Background from 'components/common/Background'
import Footer from 'components/common/Footer'
import DesktopHeader from 'components/header/DesktopHeader'
import ModalsContainer from 'components/Modals/ModalsContainer'
import PageMetadata from 'components/common/PageMetadata'
import Toaster from 'components/common/Toaster'
import DesktopHeader from 'components/header/DesktopHeader'
import ModalsContainer from 'components/Modals/ModalsContainer'
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
import { LocalStorageKeys } from 'constants/localStorageKeys'
import useLocalStorage from 'hooks/localStorage/useLocalStorage'
import useAccountId from 'hooks/useAccountId'
import useStore from 'store'
import { debugSWR } from 'utils/middleware'
interface Props {
focusComponent: FocusComponent | null
@ -62,36 +64,38 @@ export default function Layout({ children }: { children: React.ReactNode }) {
return (
<>
<PageMetadata />
<Background />
<DesktopHeader />
<main
className={classNames(
'lg:min-h-[calc(100dvh-73px)]',
'lg:mt-[73px]',
'flex',
'min-h-screen gap-6 px-4 py-6 w-full relative',
!focusComponent &&
address &&
isFullWidth &&
accountId &&
(accountDetailsExpanded ? 'pr-118' : 'pr-24'),
!reduceMotion && isFullWidth && 'transition-all duration-300',
'justify-center',
focusComponent && 'items-center',
isMobile && 'items-start',
)}
>
<Suspense>
<PageContainer focusComponent={focusComponent} fullWidth={isFullWidth}>
{children}
</PageContainer>
</Suspense>
<AccountDetails />
</main>
<Footer />
<ModalsContainer />
<Toaster />
<SWRConfig value={{ use: [debugSWR] }}>
<PageMetadata />
<Background />
<DesktopHeader />
<main
className={classNames(
'lg:min-h-[calc(100dvh-73px)]',
'lg:mt-[73px]',
'flex',
'min-h-screen gap-6 px-4 py-6 w-full relative',
!focusComponent &&
address &&
isFullWidth &&
accountId &&
(accountDetailsExpanded ? 'pr-118' : 'pr-24'),
!reduceMotion && isFullWidth && 'transition-all duration-300',
'justify-center',
focusComponent && 'items-center',
isMobile && 'items-start',
)}
>
<Suspense>
<PageContainer focusComponent={focusComponent} fullWidth={isFullWidth}>
{children}
</PageContainer>
</Suspense>
<AccountDetails />
</main>
<Footer />
<ModalsContainer />
<Toaster />
</SWRConfig>
</>
)
}

View File

@ -50,35 +50,6 @@ interface BigNumberCoin {
amount: BigNumber
}
interface BorrowMarketTableData extends MarketTableData {
liquidity: {
amount: BigNumber
value: BigNumber
} | null
debt?: BigNumber
}
interface LendingMarketTableData extends MarketTableData {
accountLentAmount?: BigNumber
accountLentValue?: BigNumber
borrowEnabled: boolean
cap: DepositCap
}
interface MarketTableData {
asset: Asset
marketDepositAmount: BigNumber
marketLiquidityAmount: BigNumber
apy: {
borrow: number
deposit: number
}
ltv: {
max: number
liq: number
}
}
interface HLSStrategy extends HLSStrategyNoCap {
depositCap: DepositCap
}

View File

@ -1,10 +1,11 @@
interface Market {
denom: string
debtTotalScaled: string
collateralTotalScaled: string
asset: Asset
cap: DepositCap // Deposits via CM
debt: BigNumber // Total outstanding debt
deposits: BigNumber // Deposits directly into the RB
liquidity: BigNumber // Available liqudiity to be borrowed
depositEnabled: boolean
borrowEnabled: boolean
cap: DepositCap
apy: {
borrow: number
deposit: number
@ -14,3 +15,12 @@ interface Market {
liq: number
}
}
interface BorrowMarketTableData extends Market {
accountDebt?: BigNumber
}
interface LendingMarketTableData extends Market {
accountLentAmount?: BigNumber
accountLentValue?: BigNumber
}

View File

@ -14,11 +14,11 @@ function isAssetPair(assetPair: Asset | AssetPair): assetPair is AssetPair {
export function sortAssetsOrPairs(
assets: Asset[] | AssetPair[],
prices: BNCoin[],
marketDeposits: BNCoin[],
markets: Market[],
balances: BNCoin[],
baseDenom: string,
): Asset[] | AssetPair[] {
if (prices.length === 0 || marketDeposits.length === 0) return assets
if (prices.length === 0 || markets.length === 0) return assets
return assets.sort((a, b) => {
const assetA = isAssetPair(a) ? a.buy : a
@ -37,8 +37,10 @@ export function sortAssetsOrPairs(
if (aDenom === baseDenom) return -1
if (bDenom === baseDenom) return 1
const aMarketDeposit = marketDeposits?.find(byDenom(aDenom))?.amount ?? BN_ZERO
const bMarketDeposit = marketDeposits?.find(byDenom(bDenom))?.amount ?? BN_ZERO
const aMarketDeposit =
markets.find((market) => market.asset.denom === aDenom)?.deposits ?? BN_ZERO
const bMarketDeposit =
markets.find((market) => market.asset.denom === bDenom)?.deposits ?? BN_ZERO
const aMarketValue = demagnify(aMarketDeposit, assetA) * aPrice.toNumber()
const bMarketValue = demagnify(bMarketDeposit, assetB) * bPrice.toNumber()

13
src/utils/middleware.ts Normal file
View File

@ -0,0 +1,13 @@
import { Middleware, SWRHook } from 'swr'
export const debugSWR: Middleware = (useSWRNext: SWRHook) => (key, fetcher, config) => {
const extendedFetcher = async (...args: any[]) => {
const startTime = Date.now()
const res = await fetcher!(...args)
process.env.NODE_ENV !== 'production' &&
console.log('⬇️ GET: ', key, ' in ', Date.now() - startTime, 'ms')
return res
}
// ...
return useSWRNext(key, extendedFetcher, config)
}

View File

@ -11,18 +11,20 @@ import { BN, getLeverageFromLTV } from 'utils/helpers'
import { convertAprToApy } from 'utils/parsers'
export function resolveMarketResponse(
marketResponse: RedBankMarket,
asset: Asset,
marketResponse: RedBankMarket & Partial<Market>,
assetParamsResponse: AssetParams,
assetCapResponse: TotalDepositResponse,
): Market {
return {
denom: marketResponse.denom,
asset,
apy: {
borrow: convertAprToApy(Number(marketResponse.borrow_rate), 365) * 100,
deposit: convertAprToApy(Number(marketResponse.liquidity_rate), 365) * 100,
},
debtTotalScaled: marketResponse.debt_total_scaled,
collateralTotalScaled: marketResponse.collateral_total_scaled,
debt: marketResponse.debt ?? BN_ZERO,
deposits: marketResponse.deposits ?? BN_ZERO,
liquidity: marketResponse.liquidity ?? BN_ZERO,
depositEnabled: assetParamsResponse.red_bank.deposit_enabled,
borrowEnabled: assetParamsResponse.red_bank.borrow_enabled,
cap: {