Mp 3270 deposit cap messages (#416)
* Add Deposit cap for AssetSelector * Add DepositCap component for Trade * DepositCap to Vault and Fund * DepositCap to Vault and Fund * Small bugixes * formatting fixes * formatting fixes * formatting fixes * formatting fixes * run format
This commit is contained in:
parent
28ccf8ba84
commit
d87fbd2a15
@ -1,12 +1,12 @@
|
||||
import { render } from '@testing-library/react'
|
||||
|
||||
import { ASSETS } from 'constants/assets'
|
||||
import { BN } from 'utils/helpers'
|
||||
import useStore from 'store'
|
||||
import DisplayCurrency from 'components/DisplayCurrency'
|
||||
import VaultBorrowings, { VaultBorrowingsProps } from 'components/Modals/Vault/VaultBorrowings'
|
||||
import { ASSETS } from 'constants/assets'
|
||||
import { TESTNET_VAULTS_META_DATA } from 'constants/vaults'
|
||||
import useStore from 'store'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { BN } from 'utils/helpers'
|
||||
|
||||
jest.mock('hooks/usePrices', () =>
|
||||
jest.fn(() => ({
|
||||
@ -58,6 +58,7 @@ describe('<VaultBorrowings />', () => {
|
||||
deposits: [],
|
||||
onChangeBorrowings: jest.fn(),
|
||||
depositActions: [],
|
||||
depositCapReachedCoins: [],
|
||||
}
|
||||
|
||||
beforeAll(() => {
|
||||
|
@ -33,9 +33,7 @@ export default async function calculateAssetIncentivesApy(
|
||||
const annualEmission = totalActiveEmissionValue.multipliedBy(SECONDS_IN_A_YEAR)
|
||||
|
||||
const totalAnnualReturnsValue = annualEmission.plus(marketReturns)
|
||||
const incentivesApy = totalAnnualReturnsValue.dividedBy(marketLiquidityValue).multipliedBy(100)
|
||||
|
||||
return incentivesApy
|
||||
return totalAnnualReturnsValue.dividedBy(marketLiquidityValue).multipliedBy(100)
|
||||
} catch (ex) {
|
||||
console.error(ex)
|
||||
return null
|
||||
|
@ -3,15 +3,16 @@ import { getParamsQueryClient, getRedBankQueryClient } from 'api/cosmwasm-client
|
||||
|
||||
export default async function getMarket(denom: string): Promise<Market> {
|
||||
try {
|
||||
const redbankClient = await getRedBankQueryClient()
|
||||
const redBankClient = await getRedBankQueryClient()
|
||||
const paramsClient = await getParamsQueryClient()
|
||||
|
||||
const [market, assetParams] = await Promise.all([
|
||||
redbankClient.market({ denom }),
|
||||
const [market, assetParams, assetCap] = await Promise.all([
|
||||
redBankClient.market({ denom }),
|
||||
paramsClient.assetParams({ denom }),
|
||||
paramsClient.totalDeposit({ denom }),
|
||||
])
|
||||
|
||||
return resolveMarketResponse(market, assetParams)
|
||||
return resolveMarketResponse(market, assetParams, assetCap)
|
||||
} catch (ex) {
|
||||
throw ex
|
||||
}
|
||||
|
@ -3,12 +3,10 @@ import { getRedBankQueryClient } from 'api/cosmwasm-client'
|
||||
export default async function getUnderlyingLiquidityAmount(market: Market): Promise<string> {
|
||||
try {
|
||||
const client = await getRedBankQueryClient()
|
||||
const marketLiquidityAmount: string = await client.underlyingLiquidityAmount({
|
||||
return await client.underlyingLiquidityAmount({
|
||||
denom: market.denom,
|
||||
amountScaled: market.collateralTotalScaled,
|
||||
})
|
||||
|
||||
return marketLiquidityAmount
|
||||
} catch (ex) {
|
||||
throw ex
|
||||
}
|
||||
|
@ -4,23 +4,31 @@ import iterateContractQuery from 'utils/iterateContractQuery'
|
||||
import { byDenom } from 'utils/array'
|
||||
import { resolveMarketResponse } from 'utils/resolvers'
|
||||
import { Market as RedBankMarket } from 'types/generated/mars-red-bank/MarsRedBank.types'
|
||||
import { AssetParamsBaseForAddr as AssetParams } from 'types/generated/mars-params/MarsParams.types'
|
||||
import {
|
||||
AssetParamsBaseForAddr as AssetParams,
|
||||
TotalDepositResponse,
|
||||
} from 'types/generated/mars-params/MarsParams.types'
|
||||
|
||||
export default async function getMarkets(): Promise<Market[]> {
|
||||
try {
|
||||
const redbankClient = await getRedBankQueryClient()
|
||||
const redBankClient = await getRedBankQueryClient()
|
||||
const paramsClient = await getParamsQueryClient()
|
||||
|
||||
const enabledAssets = getEnabledMarketAssets()
|
||||
const [markets, assetParams] = await Promise.all([
|
||||
iterateContractQuery(redbankClient.markets),
|
||||
const capQueries = enabledAssets.map((asset) =>
|
||||
paramsClient.totalDeposit({ denom: asset.denom }),
|
||||
)
|
||||
const [markets, assetParams, assetCaps] = await Promise.all([
|
||||
iterateContractQuery(redBankClient.markets),
|
||||
iterateContractQuery(paramsClient.allAssetParams),
|
||||
Promise.all(capQueries),
|
||||
])
|
||||
|
||||
return enabledAssets.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) {
|
||||
|
@ -1,8 +1,9 @@
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { useParams } from 'react-router-dom'
|
||||
|
||||
import Button from 'components/Button'
|
||||
import Card from 'components/Card'
|
||||
import DepositCapMessage from 'components/DepositCapMessage'
|
||||
import FullOverlayContent from 'components/FullOverlayContent'
|
||||
import { Plus } from 'components/Icons'
|
||||
import SwitchAutoLend from 'components/Switch/SwitchAutoLend'
|
||||
@ -12,6 +13,7 @@ import WalletBridges from 'components/Wallet/WalletBridges'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import useAccounts from 'hooks/useAccounts'
|
||||
import useCurrentAccount from 'hooks/useCurrentAccount'
|
||||
import useMarketAssets from 'hooks/useMarketAssets'
|
||||
import useToggle from 'hooks/useToggle'
|
||||
import useWalletBalances from 'hooks/useWalletBalances'
|
||||
import useStore from 'store'
|
||||
@ -19,6 +21,7 @@ import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { byDenom } from 'utils/array'
|
||||
import { getAssetByDenom, getBaseAsset } from 'utils/assets'
|
||||
import { defaultFee } from 'utils/constants'
|
||||
import { getCapLeftWithBuffer } from 'utils/generic'
|
||||
import { BN } from 'utils/helpers'
|
||||
|
||||
export default function AccountFund() {
|
||||
@ -36,6 +39,7 @@ export default function AccountFund() {
|
||||
const hasAssetSelected = fundingAssets.length > 0
|
||||
const hasFundingAssets =
|
||||
fundingAssets.length > 0 && fundingAssets.every((a) => a.toCoin().amount !== '0')
|
||||
const { data: marketAssets } = useMarketAssets()
|
||||
|
||||
const baseBalance = useMemo(
|
||||
() => walletBalances.find(byDenom(baseAsset.denom))?.amount ?? '0',
|
||||
@ -84,16 +88,15 @@ export default function AccountFund() {
|
||||
setFundingAssets(newFundingAssets)
|
||||
}, [selectedDenoms, fundingAssets])
|
||||
|
||||
const updateFundingAssets = useCallback(
|
||||
(amount: BigNumber, denom: string) => {
|
||||
const assetToUpdate = fundingAssets.find(byDenom(denom))
|
||||
if (assetToUpdate) {
|
||||
assetToUpdate.amount = amount
|
||||
setFundingAssets([...fundingAssets.filter((a) => a.denom !== denom), assetToUpdate])
|
||||
}
|
||||
},
|
||||
[fundingAssets],
|
||||
)
|
||||
const updateFundingAssets = useCallback((amount: BigNumber, denom: string) => {
|
||||
setFundingAssets((fundingAssets) => {
|
||||
const updateIdx = fundingAssets.findIndex(byDenom(denom))
|
||||
if (updateIdx === -1) return fundingAssets
|
||||
|
||||
fundingAssets[updateIdx].amount = amount
|
||||
return [...fundingAssets]
|
||||
})
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (BN(baseBalance).isLessThan(defaultFee.amount[0].amount)) {
|
||||
@ -106,6 +109,21 @@ export default function AccountFund() {
|
||||
setSelectedAccountId(currentAccount?.id ?? accountId)
|
||||
}, [accounts, selectedAccountId, accountId, currentAccount])
|
||||
|
||||
const depositCapReachedCoins = useMemo(() => {
|
||||
const depositCapReachedCoins: BNCoin[] = []
|
||||
fundingAssets.forEach((asset) => {
|
||||
const marketAsset = marketAssets.find(byDenom(asset.denom))
|
||||
if (!marketAsset) return
|
||||
|
||||
const capLeft = getCapLeftWithBuffer(marketAsset.cap)
|
||||
|
||||
if (asset.amount.isLessThanOrEqualTo(capLeft)) return
|
||||
|
||||
depositCapReachedCoins.push(BNCoin.fromDenomAndBigNumber(asset.denom, capLeft))
|
||||
})
|
||||
return depositCapReachedCoins
|
||||
}, [fundingAssets, marketAssets])
|
||||
|
||||
if (!selectedAccountId) return null
|
||||
|
||||
return (
|
||||
@ -147,6 +165,12 @@ export default function AccountFund() {
|
||||
onClick={handleSelectAssetsClick}
|
||||
disabled={isFunding}
|
||||
/>
|
||||
<DepositCapMessage
|
||||
action='fund'
|
||||
coins={depositCapReachedCoins}
|
||||
className='pr-4 py-2 mt-4'
|
||||
showIcon
|
||||
/>
|
||||
<SwitchAutoLend
|
||||
className='pt-4 mt-4 border border-transparent border-t-white/10'
|
||||
accountId={selectedAccountId}
|
||||
@ -155,7 +179,7 @@ export default function AccountFund() {
|
||||
className='w-full mt-4'
|
||||
text='Fund account'
|
||||
color='tertiary'
|
||||
disabled={!hasFundingAssets}
|
||||
disabled={!hasFundingAssets || depositCapReachedCoins.length > 0}
|
||||
showProgressIndicator={isFunding}
|
||||
onClick={handleClick}
|
||||
size='lg'
|
||||
|
50
src/components/DepositCapMessage.tsx
Normal file
50
src/components/DepositCapMessage.tsx
Normal file
@ -0,0 +1,50 @@
|
||||
import classNames from 'classnames'
|
||||
import { HTMLAttributes } from 'react'
|
||||
|
||||
import { FormattedNumber } from 'components/FormattedNumber'
|
||||
import { InfoCircle } from 'components/Icons'
|
||||
import Text from 'components/Text'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { getAssetByDenom } from 'utils/assets'
|
||||
|
||||
interface Props extends HTMLAttributes<HTMLDivElement> {
|
||||
action: 'buy' | 'deposit' | 'fund'
|
||||
coins: BNCoin[]
|
||||
showIcon?: boolean
|
||||
}
|
||||
|
||||
export default function DepositCapMessage(props: Props) {
|
||||
if (!props.coins.length) return null
|
||||
|
||||
return (
|
||||
<div className={classNames('flex items-start', props.className)}>
|
||||
{props.showIcon && <InfoCircle width={26} className='mr-5' />}
|
||||
<div className='flex-col gap-2 flex'>
|
||||
<Text size='sm'>Deposit Cap Reached</Text>
|
||||
<Text size='xs' className='text-white/40'>{`Unfortunately you're not able to ${
|
||||
props.action
|
||||
} more than the following amount${props.coins.length > 1 ? 's' : ''}:`}</Text>
|
||||
{props.coins.map((coin) => {
|
||||
const asset = getAssetByDenom(coin.denom)
|
||||
|
||||
if (!asset) return null
|
||||
|
||||
return (
|
||||
<div key={coin.denom} className='flex gap-1'>
|
||||
<Text size='xs'>Cap Left:</Text>
|
||||
<FormattedNumber
|
||||
amount={coin.amount.toNumber()}
|
||||
options={{
|
||||
abbreviated: true,
|
||||
decimals: asset.decimals,
|
||||
suffix: ` ${asset.symbol}`,
|
||||
}}
|
||||
className='text-white/60 text-xs'
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
import { useMemo } from 'react'
|
||||
import classNames from 'classnames'
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import { FormattedNumber } from 'components/FormattedNumber'
|
||||
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
||||
@ -14,7 +14,7 @@ interface Props {
|
||||
coin: BNCoin
|
||||
className?: string
|
||||
isApproximation?: boolean
|
||||
parantheses?: boolean
|
||||
parentheses?: boolean
|
||||
}
|
||||
|
||||
export default function DisplayCurrency(props: Props) {
|
||||
@ -43,7 +43,7 @@ export default function DisplayCurrency(props: Props) {
|
||||
<FormattedNumber
|
||||
className={classNames(
|
||||
props.className,
|
||||
props.parantheses && 'before:content-["("] after:content-[")"]',
|
||||
props.parentheses && 'before:content-["("] after:content-[")"]',
|
||||
)}
|
||||
amount={convertToDisplayAmount(props.coin, displayCurrency, prices).toNumber()}
|
||||
options={{
|
||||
|
@ -107,7 +107,7 @@ export default function VaultExpanded(props: Props) {
|
||||
!isExpanded && props.row.toggleExpanded()
|
||||
}}
|
||||
>
|
||||
<td colSpan={!status ? 5 : 6}>
|
||||
<td colSpan={!status ? 7 : 8}>
|
||||
<div className='align-center flex justify-end gap-3 p-4'>
|
||||
{status && <DepositMoreButton />}
|
||||
{status === VaultStatus.ACTIVE && <UnlockButton />}
|
||||
|
@ -182,6 +182,7 @@ export const VaultTable = (props: Props) => {
|
||||
accessorKey: 'ltv.max',
|
||||
header: 'Max LTV',
|
||||
cell: ({ row }) => {
|
||||
if (props.isLoading) return <Loading />
|
||||
return <Text className='text-xs'>{formatPercent(row.original.ltv.max)}</Text>
|
||||
},
|
||||
},
|
||||
@ -189,6 +190,7 @@ export const VaultTable = (props: Props) => {
|
||||
accessorKey: 'ltv.liq',
|
||||
header: 'Liq. LTV',
|
||||
cell: ({ row }) => {
|
||||
if (props.isLoading) return <Loading />
|
||||
return <Text className='text-xs'>{formatPercent(row.original.ltv.liq)}</Text>
|
||||
},
|
||||
},
|
||||
|
@ -9,11 +9,11 @@ import Settings from 'components/Settings'
|
||||
import Wallet from 'components/Wallet'
|
||||
import useStore from 'store'
|
||||
|
||||
export const menuTree: { page: Page; label: string }[] = [
|
||||
{ page: 'trade', label: 'Trade' },
|
||||
{ page: 'lend', label: 'Earn' },
|
||||
{ page: 'borrow', label: 'Borrow' },
|
||||
{ page: 'portfolio', label: 'Portfolio' },
|
||||
export const menuTree: { pages: Page[]; label: string }[] = [
|
||||
{ pages: ['trade'], label: 'Trade' },
|
||||
{ pages: ['lend', 'farm'], label: 'Earn' },
|
||||
{ pages: ['borrow'], label: 'Borrow' },
|
||||
{ pages: ['portfolio'], label: 'Portfolio' },
|
||||
]
|
||||
|
||||
export default function DesktopHeader() {
|
||||
|
@ -207,7 +207,7 @@ function BorrowModal(props: Props) {
|
||||
asset.denom,
|
||||
modal.marketData?.liquidity?.amount ?? BN_ZERO,
|
||||
)}
|
||||
parantheses
|
||||
parentheses
|
||||
/>
|
||||
</div>
|
||||
<Text size='xs' className='text-white/50' tag='span'>
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
|
||||
import Button from 'components/Button'
|
||||
import DepositCapMessage from 'components/DepositCapMessage'
|
||||
import { ArrowRight, Plus } from 'components/Icons'
|
||||
import SwitchAutoLend from 'components/Switch/SwitchAutoLend'
|
||||
import Text from 'components/Text'
|
||||
@ -8,6 +9,7 @@ import TokenInputWithSlider from 'components/TokenInput/TokenInputWithSlider'
|
||||
import WalletBridges from 'components/Wallet/WalletBridges'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import useAutoLendEnabledAccountIds from 'hooks/useAutoLendEnabledAccountIds'
|
||||
import useMarketAssets from 'hooks/useMarketAssets'
|
||||
import useToggle from 'hooks/useToggle'
|
||||
import { useUpdatedAccount } from 'hooks/useUpdatedAccount'
|
||||
import useWalletBalances from 'hooks/useWalletBalances'
|
||||
@ -16,6 +18,7 @@ import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { byDenom } from 'utils/array'
|
||||
import { getAssetByDenom, getBaseAsset } from 'utils/assets'
|
||||
import { defaultFee } from 'utils/constants'
|
||||
import { getCapLeftWithBuffer } from 'utils/generic'
|
||||
import { BN } from 'utils/helpers'
|
||||
|
||||
interface Props {
|
||||
@ -38,7 +41,7 @@ export default function FundAccount(props: Props) {
|
||||
const { autoLendEnabledAccountIds } = useAutoLendEnabledAccountIds()
|
||||
const isAutoLendEnabled = autoLendEnabledAccountIds.includes(accountId)
|
||||
const { simulateDeposits } = useUpdatedAccount(account)
|
||||
|
||||
const { data: marketAssets } = useMarketAssets()
|
||||
const baseBalance = useMemo(
|
||||
() => walletBalances.find(byDenom(baseAsset.denom))?.amount ?? '0',
|
||||
[walletBalances, baseAsset],
|
||||
@ -87,16 +90,15 @@ export default function FundAccount(props: Props) {
|
||||
setFundingAssets(newFundingAssets)
|
||||
}, [selectedDenoms, fundingAssets])
|
||||
|
||||
const updateFundingAssets = useCallback(
|
||||
(amount: BigNumber, denom: string) => {
|
||||
const assetToUpdate = fundingAssets.find(byDenom(denom))
|
||||
if (assetToUpdate) {
|
||||
assetToUpdate.amount = amount
|
||||
setFundingAssets([...fundingAssets.filter((a) => a.denom !== denom), assetToUpdate])
|
||||
}
|
||||
},
|
||||
[fundingAssets],
|
||||
)
|
||||
const updateFundingAssets = useCallback((amount: BigNumber, denom: string) => {
|
||||
setFundingAssets((fundingAssets) => {
|
||||
const updateIdx = fundingAssets.findIndex(byDenom(denom))
|
||||
if (updateIdx === -1) return fundingAssets
|
||||
|
||||
fundingAssets[updateIdx].amount = amount
|
||||
return [...fundingAssets]
|
||||
})
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
simulateDeposits(isAutoLendEnabled ? 'lend' : 'deposit', fundingAssets)
|
||||
@ -108,6 +110,21 @@ export default function FundAccount(props: Props) {
|
||||
}
|
||||
}, [baseBalance])
|
||||
|
||||
const depositCapReachedCoins = useMemo(() => {
|
||||
const depositCapReachedCoins: BNCoin[] = []
|
||||
fundingAssets.forEach((asset) => {
|
||||
const marketAsset = marketAssets.find(byDenom(asset.denom))
|
||||
if (!marketAsset) return
|
||||
|
||||
const capLeft = getCapLeftWithBuffer(marketAsset.cap)
|
||||
|
||||
if (asset.amount.isLessThanOrEqualTo(capLeft)) return
|
||||
|
||||
depositCapReachedCoins.push(BNCoin.fromDenomAndBigNumber(asset.denom, capLeft))
|
||||
})
|
||||
return depositCapReachedCoins
|
||||
}, [fundingAssets, marketAssets])
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='flex flex-wrap items-start'>
|
||||
@ -139,6 +156,12 @@ export default function FundAccount(props: Props) {
|
||||
onClick={handleSelectAssetsClick}
|
||||
disabled={isFunding}
|
||||
/>
|
||||
<DepositCapMessage
|
||||
action='fund'
|
||||
coins={depositCapReachedCoins}
|
||||
className='pr-4 py-2 mt-4'
|
||||
showIcon
|
||||
/>
|
||||
<SwitchAutoLend
|
||||
className='pt-4 mt-4 border border-transparent border-t-white/10'
|
||||
accountId={accountId}
|
||||
@ -148,7 +171,7 @@ export default function FundAccount(props: Props) {
|
||||
className='w-full mt-4'
|
||||
text='Fund account'
|
||||
rightIcon={<ArrowRight />}
|
||||
disabled={!hasFundingAssets}
|
||||
disabled={!hasFundingAssets || depositCapReachedCoins.length > 0}
|
||||
showProgressIndicator={isFunding}
|
||||
onClick={handleClick}
|
||||
/>
|
||||
|
@ -2,6 +2,7 @@ import BigNumber from 'bignumber.js'
|
||||
import React, { useEffect, useMemo, useState } from 'react'
|
||||
|
||||
import Button from 'components/Button'
|
||||
import DepositCapMessage from 'components/DepositCapMessage'
|
||||
import DisplayCurrency from 'components/DisplayCurrency'
|
||||
import Divider from 'components/Divider'
|
||||
import { ArrowRight, ExclamationMarkCircled } from 'components/Icons'
|
||||
@ -27,6 +28,7 @@ export interface VaultBorrowingsProps {
|
||||
vault: Vault
|
||||
depositActions: Action[]
|
||||
onChangeBorrowings: (borrowings: BNCoin[]) => void
|
||||
depositCapReachedCoins: BNCoin[]
|
||||
}
|
||||
|
||||
export default function VaultBorrowings(props: VaultBorrowingsProps) {
|
||||
@ -187,12 +189,21 @@ export default function VaultBorrowings(props: VaultBorrowingsProps) {
|
||||
</Text>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Button
|
||||
text='Select borrow assets +'
|
||||
color='tertiary'
|
||||
onClick={addAsset}
|
||||
disabled={isConfirming}
|
||||
/>
|
||||
|
||||
<DepositCapMessage
|
||||
action='deposit'
|
||||
coins={props.depositCapReachedCoins}
|
||||
className='px-4 y-2'
|
||||
showIcon
|
||||
/>
|
||||
|
||||
<Divider />
|
||||
<div className='flex flex-col gap-2'>
|
||||
<div className='flex justify-between'>
|
||||
@ -221,7 +232,7 @@ export default function VaultBorrowings(props: VaultBorrowingsProps) {
|
||||
text='Deposit'
|
||||
rightIcon={<ArrowRight />}
|
||||
showProgressIndicator={isConfirming}
|
||||
disabled={!props.depositActions.length}
|
||||
disabled={!props.depositActions.length || props.depositCapReachedCoins.length > 0}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
@ -1,7 +1,7 @@
|
||||
import BigNumber from 'bignumber.js'
|
||||
import { useMemo, useState } from 'react'
|
||||
|
||||
import Button from 'components/Button'
|
||||
import DepositCapMessage from 'components/DepositCapMessage'
|
||||
import DisplayCurrency from 'components/DisplayCurrency'
|
||||
import Divider from 'components/Divider'
|
||||
import { Gauge } from 'components/Gauge'
|
||||
@ -12,6 +12,7 @@ import Text from 'components/Text'
|
||||
import TokenInput from 'components/TokenInput'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import usePrice from 'hooks/usePrice'
|
||||
import { useMemo, useState } from 'react'
|
||||
import useStore from 'store'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { accumulateAmounts } from 'utils/accounts'
|
||||
@ -27,6 +28,7 @@ interface Props {
|
||||
onChangeDeposits: (deposits: BNCoin[]) => void
|
||||
onChangeIsCustomRatio: (isCustomRatio: boolean) => void
|
||||
toggleOpen: (index: number) => void
|
||||
depositCapReachedCoins: BNCoin[]
|
||||
}
|
||||
|
||||
export default function VaultDeposit(props: Props) {
|
||||
@ -158,7 +160,7 @@ export default function VaultDeposit(props: Props) {
|
||||
|
||||
return (
|
||||
<div className='flex flex-col'>
|
||||
<div className='flex gap-4 p-4'>
|
||||
<div className='flex gap-4 pl-3 p-4'>
|
||||
<div className='flex flex-col items-center justify-between gap-1 pb-[30px] pt-2'>
|
||||
<Gauge
|
||||
percentage={primaryValuePercentage}
|
||||
@ -202,6 +204,14 @@ export default function VaultDeposit(props: Props) {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<DepositCapMessage
|
||||
action='deposit'
|
||||
coins={props.depositCapReachedCoins}
|
||||
className='px-4 "y-2'
|
||||
showIcon
|
||||
/>
|
||||
|
||||
<div className='flex flex-col gap-6 p-4 pt-2'>
|
||||
{disableInput ? (
|
||||
<div>
|
||||
@ -240,4 +250,4 @@ export default function VaultDeposit(props: Props) {
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
|
||||
import Accordion from 'components/Accordion'
|
||||
import AccountSummary from 'components/Account/AccountSummary'
|
||||
@ -8,10 +8,14 @@ import VaultDeposit from 'components/Modals/Vault/VaultDeposits'
|
||||
import VaultDepositSubTitle from 'components/Modals/Vault/VaultDepositsSubTitle'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import useDepositVault from 'hooks/broadcast/useDepositVault'
|
||||
import useDisplayAsset from 'hooks/useDisplayAsset'
|
||||
import useIsOpenArray from 'hooks/useIsOpenArray'
|
||||
import usePrices from 'hooks/usePrices'
|
||||
import { useUpdatedAccount } from 'hooks/useUpdatedAccount'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { byDenom } from 'utils/array'
|
||||
import { convertToDisplayAmount, magnify } from 'utils/formatters'
|
||||
import { getCapLeftWithBuffer } from 'utils/generic'
|
||||
|
||||
interface Props {
|
||||
vault: Vault | DepositedVault
|
||||
@ -29,14 +33,14 @@ export default function VaultModalContent(props: Props) {
|
||||
removedDeposits,
|
||||
removedLends,
|
||||
removeLends,
|
||||
updatedAccount,
|
||||
addVaultValues,
|
||||
} = useUpdatedAccount(props.account)
|
||||
|
||||
const { data: prices } = usePrices()
|
||||
const [isOpen, toggleOpen] = useIsOpenArray(2, false)
|
||||
const [isCustomRatio, setIsCustomRatio] = useState(false)
|
||||
const [selectedCoins, setSelectedCoins] = useState<BNCoin[]>([])
|
||||
|
||||
const displayAsset = useDisplayAsset()
|
||||
const { actions: depositActions, totalValue } = useDepositVault({
|
||||
vault: props.vault,
|
||||
reclaims: removedLends,
|
||||
@ -44,6 +48,24 @@ export default function VaultModalContent(props: Props) {
|
||||
borrowings: addedDebts,
|
||||
})
|
||||
|
||||
const depositCapReachedCoins = useMemo(() => {
|
||||
const capLeft = getCapLeftWithBuffer(props.vault.cap)
|
||||
|
||||
if (totalValue.isGreaterThan(capLeft)) {
|
||||
const amount = magnify(
|
||||
convertToDisplayAmount(
|
||||
BNCoin.fromDenomAndBigNumber(props.vault.cap.denom, capLeft),
|
||||
displayAsset.denom,
|
||||
prices,
|
||||
).toString(),
|
||||
displayAsset,
|
||||
)
|
||||
|
||||
return [BNCoin.fromDenomAndBigNumber(displayAsset.denom, amount)]
|
||||
}
|
||||
return []
|
||||
}, [displayAsset, prices, props.vault.cap, totalValue])
|
||||
|
||||
const handleDepositSelect = useCallback(
|
||||
(selectedCoins: BNCoin[]) => {
|
||||
const reclaims: BNCoin[] = []
|
||||
@ -134,6 +156,7 @@ export default function VaultModalContent(props: Props) {
|
||||
toggleOpen={toggleOpen}
|
||||
isCustomRatio={isCustomRatio}
|
||||
onChangeIsCustomRatio={onChangeIsCustomRatio}
|
||||
depositCapReachedCoins={depositCapReachedCoins}
|
||||
/>
|
||||
),
|
||||
title: 'Deposit',
|
||||
@ -151,6 +174,7 @@ export default function VaultModalContent(props: Props) {
|
||||
onChangeBorrowings={addDebts}
|
||||
vault={props.vault}
|
||||
depositActions={depositActions}
|
||||
depositCapReachedCoins={depositCapReachedCoins}
|
||||
/>
|
||||
),
|
||||
title: 'Borrow',
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { useParams } from 'react-router-dom'
|
||||
import classNames from 'classnames'
|
||||
import { useParams } from 'react-router-dom'
|
||||
|
||||
import { menuTree } from 'components/Header/DesktopHeader'
|
||||
import { Logo } from 'components/Icons'
|
||||
@ -11,8 +11,8 @@ export default function DesktopNavigation() {
|
||||
const { address, accountId } = useParams()
|
||||
const focusComponent = useStore((s) => s.focusComponent)
|
||||
|
||||
function getIsActive(href: string) {
|
||||
return location.pathname.includes(href)
|
||||
function getIsActive(pages: string[]) {
|
||||
return pages.some((page) => location.pathname.includes(page))
|
||||
}
|
||||
|
||||
return (
|
||||
@ -31,8 +31,8 @@ export default function DesktopNavigation() {
|
||||
{menuTree.map((item, index) => (
|
||||
<NavLink
|
||||
key={index}
|
||||
href={getRoute(item.page, address, accountId)}
|
||||
isActive={getIsActive(item.page)}
|
||||
href={getRoute(item.pages[0], address, accountId)}
|
||||
isActive={getIsActive(item.pages)}
|
||||
>
|
||||
{item.label}
|
||||
</NavLink>
|
||||
|
@ -12,12 +12,10 @@ export const NavLink = (props: Props) => {
|
||||
return (
|
||||
<Link
|
||||
to={props.href}
|
||||
className={({ isActive }) =>
|
||||
classNames(
|
||||
'text-sm font-semibold hover:text-white active:text-white',
|
||||
isActive ? 'pointer-events-none text-white' : 'text-white/60',
|
||||
)
|
||||
}
|
||||
className={classNames(
|
||||
'text-sm font-semibold hover:text-white active:text-white',
|
||||
props.isActive ? 'pointer-events-none text-white' : 'text-white/60',
|
||||
)}
|
||||
>
|
||||
{props.children}
|
||||
</Link>
|
||||
|
@ -10,6 +10,7 @@ import { BNCoin } from 'types/classes/BNCoin'
|
||||
interface Props {
|
||||
asset: Asset
|
||||
onSelectAsset: (asset: Asset) => void
|
||||
depositCap?: DepositCap
|
||||
}
|
||||
|
||||
export default function AssetItem(props: Props) {
|
||||
@ -40,11 +41,24 @@ export default function AssetItem(props: Props) {
|
||||
{asset.isFavorite ? <StarFilled width={16} /> : <StarOutlined width={16} />}
|
||||
</div>
|
||||
<AssetImage asset={asset} size={24} />
|
||||
<Text size='sm' className='text-left'>
|
||||
{asset.name}
|
||||
</Text>
|
||||
<div className='rounded-sm bg-white/20 px-[6px] py-[2px]'>
|
||||
<Text size='xs'>{asset.symbol}</Text>
|
||||
<div className='flex-col'>
|
||||
<div className='flex gap-1'>
|
||||
<Text size='sm' className='text-left'>
|
||||
{asset.name}
|
||||
</Text>
|
||||
<div className='rounded-sm bg-white/20 px-[6px] py-[2px]'>
|
||||
<Text size='xs'>{asset.symbol}</Text>
|
||||
</div>
|
||||
</div>
|
||||
{props.depositCap && (
|
||||
<div className='flex gap-1'>
|
||||
<span className='text-left text-white/60 text-xs'>Cap Left: </span>
|
||||
<DisplayCurrency
|
||||
className='text-left text-white/60 text-xs'
|
||||
coin={BNCoin.fromDenomAndBigNumber(props.depositCap.denom, props.depositCap.max)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<DisplayCurrency
|
||||
|
@ -3,6 +3,8 @@ import classNames from 'classnames'
|
||||
import { ChevronDown } from 'components/Icons'
|
||||
import Text from 'components/Text'
|
||||
import AssetItem from 'components/Trade/TradeModule/AssetSelector/AssetItem'
|
||||
import useMarketAssets from 'hooks/useMarketAssets'
|
||||
import { byDenom } from 'utils/array'
|
||||
|
||||
interface Props {
|
||||
type: 'buy' | 'sell'
|
||||
@ -13,6 +15,8 @@ interface Props {
|
||||
}
|
||||
|
||||
export default function AssetList(props: Props) {
|
||||
const { data: marketAssets } = useMarketAssets()
|
||||
|
||||
return (
|
||||
<section>
|
||||
<button
|
||||
@ -34,6 +38,9 @@ export default function AssetList(props: Props) {
|
||||
key={`${props.type}-${asset.symbol}`}
|
||||
asset={asset}
|
||||
onSelectAsset={props.onChangeAsset}
|
||||
depositCap={
|
||||
props.type === 'buy' ? marketAssets?.find(byDenom(asset.denom))?.cap : undefined
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</ul>
|
||||
|
@ -4,8 +4,8 @@ import { InfoCircle } from 'components/Icons'
|
||||
import Text from 'components/Text'
|
||||
import { Tooltip } from 'components/Tooltip'
|
||||
import { ORDER_TYPE_TABS } from 'components/Trade/TradeModule/SwapForm/OrderTypeSelector/constants'
|
||||
import ConditionalWrapper from 'hocs/ConditionalWrapper'
|
||||
import { AvailableOrderType } from 'components/Trade/TradeModule/SwapForm/OrderTypeSelector/types'
|
||||
import ConditionalWrapper from 'hocs/ConditionalWrapper'
|
||||
|
||||
interface Props {
|
||||
selected: AvailableOrderType
|
||||
@ -46,9 +46,9 @@ export default function OrderTypeSelector(props: Props) {
|
||||
}
|
||||
|
||||
const className = {
|
||||
wrapper: 'flex flex-1 flex-row px-3 pt-3',
|
||||
wrapper: 'flex flex-1 flex-row px-3 pt-4',
|
||||
tab: 'mr-4 pb-2 cursor-pointer select-none flex flex-row',
|
||||
selectedTab: 'border-b-2 border-pink border-solid',
|
||||
disabledTab: 'opacity-50 pointer-events-none',
|
||||
disabledTab: 'opacity-20 pointer-events-none',
|
||||
infoCircle: 'w-4 h-4 ml-2 mt-1',
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import debounce from 'lodash.debounce'
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
|
||||
import estimateExactIn from 'api/swap/estimateExactIn'
|
||||
import DepositCapMessage from 'components/DepositCapMessage'
|
||||
import Divider from 'components/Divider'
|
||||
import RangeInput from 'components/RangeInput'
|
||||
import AssetAmountInput from 'components/Trade/TradeModule/SwapForm/AssetAmountInput'
|
||||
@ -16,6 +17,7 @@ import useAutoLendEnabledAccountIds from 'hooks/useAutoLendEnabledAccountIds'
|
||||
import useCurrentAccount from 'hooks/useCurrentAccount'
|
||||
import useHealthComputer from 'hooks/useHealthComputer'
|
||||
import useLocalStorage from 'hooks/useLocalStorage'
|
||||
import useMarketAssets from 'hooks/useMarketAssets'
|
||||
import useMarketBorrowings from 'hooks/useMarketBorrowings'
|
||||
import usePrices from 'hooks/usePrices'
|
||||
import useToggle from 'hooks/useToggle'
|
||||
@ -24,6 +26,7 @@ import useStore from 'store'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { byDenom } from 'utils/array'
|
||||
import { defaultFee } from 'utils/constants'
|
||||
import { getCapLeftWithBuffer } from 'utils/generic'
|
||||
import { asyncThrottle, BN } from 'utils/helpers'
|
||||
|
||||
interface Props {
|
||||
@ -39,6 +42,7 @@ export default function SwapForm(props: Props) {
|
||||
const [slippage] = useLocalStorage(SLIPPAGE_KEY, DEFAULT_SETTINGS.slippage)
|
||||
const { computeMaxSwapAmount } = useHealthComputer(account)
|
||||
const { data: borrowAssets } = useMarketBorrowings()
|
||||
const { data: marketAssets } = useMarketAssets()
|
||||
|
||||
const [isMarginChecked, setMarginChecked] = useToggle()
|
||||
const [buyAssetAmount, setBuyAssetAmount] = useState(BN_ZERO)
|
||||
@ -58,6 +62,19 @@ export default function SwapForm(props: Props) {
|
||||
[borrowAssets, sellAsset.denom],
|
||||
)
|
||||
|
||||
const depositCapReachedCoins: BNCoin[] = useMemo(() => {
|
||||
const buyMarketAsset = marketAssets.find(byDenom(buyAsset.denom))
|
||||
|
||||
if (!buyMarketAsset) return []
|
||||
|
||||
const depositCapLeft = getCapLeftWithBuffer(buyMarketAsset.cap)
|
||||
if (buyAssetAmount.isGreaterThan(depositCapLeft)) {
|
||||
return [BNCoin.fromDenomAndBigNumber(buyAsset.denom, depositCapLeft)]
|
||||
}
|
||||
|
||||
return []
|
||||
}, [marketAssets, buyAsset.denom, buyAssetAmount])
|
||||
|
||||
const onChangeSellAmount = useCallback(
|
||||
(amount: BigNumber) => {
|
||||
setSellAssetAmount(amount)
|
||||
@ -233,59 +250,59 @@ export default function SwapForm(props: Props) {
|
||||
/>
|
||||
<Divider />
|
||||
<OrderTypeSelector selected={selectedOrderType} onChange={setSelectedOrderType} />
|
||||
<AssetAmountInput
|
||||
label='Buy'
|
||||
max={maxBuyableAmountEstimation}
|
||||
amount={buyAssetAmount}
|
||||
setAmount={onChangeBuyAmount}
|
||||
asset={buyAsset}
|
||||
assetUSDValue={buyAssetValue}
|
||||
maxButtonLabel='Max Amount:'
|
||||
containerClassName='mx-3 my-6'
|
||||
disabled={isConfirming}
|
||||
/>
|
||||
<div className='flex flex-col gap-6 px-3 mt-6'>
|
||||
<AssetAmountInput
|
||||
label='Buy'
|
||||
max={maxBuyableAmountEstimation}
|
||||
amount={buyAssetAmount}
|
||||
setAmount={onChangeBuyAmount}
|
||||
asset={buyAsset}
|
||||
assetUSDValue={buyAssetValue}
|
||||
maxButtonLabel='Max Amount:'
|
||||
disabled={isConfirming}
|
||||
/>
|
||||
|
||||
<RangeInput
|
||||
wrapperClassName='p-4'
|
||||
disabled={isConfirming || maxBuyableAmountEstimation.isZero()}
|
||||
onChange={handleRangeInputChange}
|
||||
value={buyAssetAmount.shiftedBy(-buyAsset.decimals).toNumber()}
|
||||
max={maxBuyableAmountEstimation.shiftedBy(-buyAsset.decimals).toNumber()}
|
||||
marginThreshold={
|
||||
isMarginChecked
|
||||
? buySideMarginThreshold.shiftedBy(-buyAsset.decimals).toNumber()
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
<RangeInput
|
||||
disabled={isConfirming || maxBuyableAmountEstimation.isZero()}
|
||||
onChange={handleRangeInputChange}
|
||||
value={buyAssetAmount.shiftedBy(-buyAsset.decimals).toNumber()}
|
||||
max={maxBuyableAmountEstimation.shiftedBy(-buyAsset.decimals).toNumber()}
|
||||
marginThreshold={
|
||||
isMarginChecked
|
||||
? buySideMarginThreshold.shiftedBy(-buyAsset.decimals).toNumber()
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
|
||||
<AssetAmountInput
|
||||
label='Sell'
|
||||
max={maxSellAmount}
|
||||
amount={sellAssetAmount}
|
||||
setAmount={onChangeSellAmount}
|
||||
assetUSDValue={sellAssetValue}
|
||||
asset={sellAsset}
|
||||
maxButtonLabel='Balance:'
|
||||
containerClassName='mx-3'
|
||||
disabled={isConfirming}
|
||||
/>
|
||||
<DepositCapMessage action='buy' coins={depositCapReachedCoins} className='p-4 bg-white/5' />
|
||||
|
||||
<TradeSummary
|
||||
containerClassName='m-3 mt-10'
|
||||
buyAsset={buyAsset}
|
||||
sellAsset={sellAsset}
|
||||
borrowRate={borrowAsset?.borrowRate}
|
||||
buyAction={handleBuyClick}
|
||||
buyButtonDisabled={sellAssetAmount.isZero()}
|
||||
showProgressIndicator={isConfirming}
|
||||
isMargin={isMarginChecked}
|
||||
borrowAmount={
|
||||
sellAssetAmount.isGreaterThan(sellSideMarginThreshold)
|
||||
? sellAssetAmount.minus(sellSideMarginThreshold)
|
||||
: BN_ZERO
|
||||
}
|
||||
estimatedFee={estimatedFee}
|
||||
/>
|
||||
<AssetAmountInput
|
||||
label='Sell'
|
||||
max={maxSellAmount}
|
||||
amount={sellAssetAmount}
|
||||
setAmount={onChangeSellAmount}
|
||||
assetUSDValue={sellAssetValue}
|
||||
asset={sellAsset}
|
||||
maxButtonLabel='Balance:'
|
||||
disabled={isConfirming}
|
||||
/>
|
||||
|
||||
<TradeSummary
|
||||
buyAsset={buyAsset}
|
||||
sellAsset={sellAsset}
|
||||
borrowRate={borrowAsset?.borrowRate}
|
||||
buyAction={handleBuyClick}
|
||||
buyButtonDisabled={sellAssetAmount.isZero() || depositCapReachedCoins.length > 0}
|
||||
showProgressIndicator={isConfirming}
|
||||
isMargin={isMarginChecked}
|
||||
borrowAmount={
|
||||
sellAssetAmount.isGreaterThan(sellSideMarginThreshold)
|
||||
? sellAssetAmount.minus(sellSideMarginThreshold)
|
||||
: BN_ZERO
|
||||
}
|
||||
estimatedFee={estimatedFee}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
14
src/hooks/useDisplayAsset.tsx
Normal file
14
src/hooks/useDisplayAsset.tsx
Normal file
@ -0,0 +1,14 @@
|
||||
import { ASSETS } from 'constants/assets'
|
||||
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
||||
import { DISPLAY_CURRENCY_KEY } from 'constants/localStore'
|
||||
import useLocalStorage from 'hooks/useLocalStorage'
|
||||
import { byDenom } from 'utils/array'
|
||||
|
||||
export default function useDisplayAsset() {
|
||||
const [displayCurrency] = useLocalStorage<string>(
|
||||
DISPLAY_CURRENCY_KEY,
|
||||
DEFAULT_SETTINGS.displayCurrency,
|
||||
)
|
||||
|
||||
return ASSETS.find(byDenom(displayCurrency)) ?? ASSETS[0]
|
||||
}
|
@ -15,6 +15,7 @@ import {
|
||||
HealthComputer,
|
||||
} from 'types/generated/mars-rover-health-computer/MarsRoverHealthComputer.types'
|
||||
import { convertAccountToPositions } from 'utils/accounts'
|
||||
import { LTV_BUFFER } from 'utils/constants'
|
||||
import {
|
||||
BorrowTarget,
|
||||
compute_health_js,
|
||||
@ -24,7 +25,6 @@ import {
|
||||
SwapKind,
|
||||
} from 'utils/health_computer'
|
||||
import { BN } from 'utils/helpers'
|
||||
import { LTV_BUFFER } from 'utils/constants'
|
||||
|
||||
export default function useHealthComputer(account?: Account) {
|
||||
const { data: prices } = usePrices()
|
||||
|
@ -23,7 +23,7 @@ function useLendingMarketAssetsTableData(): {
|
||||
const accountLentAssets: LendingMarketTableData[] = [],
|
||||
availableAssets: LendingMarketTableData[] = []
|
||||
|
||||
markets.forEach(({ denom, depositCap, liquidityRate, liquidationThreshold, maxLtv }) => {
|
||||
markets.forEach(({ denom, cap, liquidityRate, liquidationThreshold, maxLtv }) => {
|
||||
const asset = getAssetByDenom(denom) as Asset
|
||||
const marketDepositAmount = BN(marketDeposits.find(byDenom(denom))?.amount ?? 0)
|
||||
const marketLiquidityAmount = BN(marketLiquidities.find(byDenom(denom))?.amount ?? 0)
|
||||
@ -38,7 +38,7 @@ function useLendingMarketAssetsTableData(): {
|
||||
accountLentValue,
|
||||
accountLentAmount,
|
||||
marketLiquidityAmount,
|
||||
marketDepositCap: BN(depositCap),
|
||||
marketDepositCap: cap.max,
|
||||
marketLiquidityRate: liquidityRate,
|
||||
marketLiquidationThreshold: liquidationThreshold,
|
||||
marketMaxLtv: maxLtv,
|
||||
|
4
src/types/interfaces/asset.d.ts
vendored
4
src/types/interfaces/asset.d.ts
vendored
@ -49,10 +49,6 @@ interface PseudoAsset {
|
||||
symbol: string
|
||||
}
|
||||
|
||||
interface OtherAsset extends Omit<Asset, 'symbol'> {
|
||||
symbol: 'MARS'
|
||||
}
|
||||
|
||||
interface BorrowAsset extends Asset {
|
||||
borrowRate: number | null
|
||||
liquidity: {
|
||||
|
2
src/types/interfaces/market.d.ts
vendored
2
src/types/interfaces/market.d.ts
vendored
@ -5,7 +5,7 @@ interface Market {
|
||||
collateralTotalScaled: string
|
||||
depositEnabled: boolean
|
||||
borrowEnabled: boolean
|
||||
depositCap: string
|
||||
cap: DepositCap
|
||||
maxLtv: number
|
||||
liquidityRate: number
|
||||
liquidationThreshold: number
|
||||
|
12
src/types/interfaces/vaults.d.ts
vendored
12
src/types/interfaces/vaults.d.ts
vendored
@ -26,11 +26,7 @@ interface VaultInfo {
|
||||
max: number
|
||||
liq: number
|
||||
}
|
||||
cap: {
|
||||
denom: string
|
||||
used: BigNumber
|
||||
max: BigNumber
|
||||
}
|
||||
cap: DepositCap
|
||||
}
|
||||
|
||||
interface VaultConfig extends VaultMetaData, VaultInfo {}
|
||||
@ -74,3 +70,9 @@ interface VaultPositionFlatAmounts {
|
||||
unlocking: BigNumber
|
||||
unlocked: BigNumber
|
||||
}
|
||||
|
||||
interface DepositCap {
|
||||
denom: string
|
||||
used: BigNumber
|
||||
max: BigNumber
|
||||
}
|
||||
|
@ -11,3 +11,5 @@ export const defaultFee: StdFee = {
|
||||
export const SECONDS_IN_A_YEAR = 31540000
|
||||
|
||||
export const LTV_BUFFER = 0.01
|
||||
|
||||
export const DEPOSIT_CAP_BUFFER = 0.999
|
||||
|
5
src/utils/generic.ts
Normal file
5
src/utils/generic.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { DEPOSIT_CAP_BUFFER } from 'utils/constants'
|
||||
|
||||
export function getCapLeftWithBuffer(cap: DepositCap) {
|
||||
return cap.max.minus(cap.used).times(DEPOSIT_CAP_BUFFER).integerValue()
|
||||
}
|
@ -1,9 +1,14 @@
|
||||
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 { AssetParamsBaseForAddr as AssetParams } from 'types/generated/mars-params/MarsParams.types'
|
||||
import { BN } from 'utils/helpers'
|
||||
|
||||
export function resolveMarketResponse(
|
||||
marketResponse: RedBankMarket,
|
||||
assetParamsResponse: AssetParams,
|
||||
assetCapResponse: TotalDepositResponse,
|
||||
): Market {
|
||||
return {
|
||||
denom: marketResponse.denom,
|
||||
@ -12,7 +17,11 @@ export function resolveMarketResponse(
|
||||
collateralTotalScaled: marketResponse.collateral_total_scaled,
|
||||
depositEnabled: assetParamsResponse.red_bank.deposit_enabled,
|
||||
borrowEnabled: assetParamsResponse.red_bank.borrow_enabled,
|
||||
depositCap: assetParamsResponse.deposit_cap,
|
||||
cap: {
|
||||
denom: assetCapResponse.denom,
|
||||
used: BN(assetCapResponse.amount),
|
||||
max: BN(assetParamsResponse.deposit_cap),
|
||||
},
|
||||
maxLtv: Number(assetParamsResponse.max_loan_to_value),
|
||||
liquidityRate: Number(marketResponse.liquidity_rate),
|
||||
liquidationThreshold: Number(assetParamsResponse.liquidation_threshold),
|
||||
|
Loading…
Reference in New Issue
Block a user