Max margin trade fix (#490)
* fix: margin trading fix * fix: accountsBalancesTable fix * fix: show detailed APR where we have the space * fix: smallerThan not biggerThan * fix: be more precise on the decimals * tidy: refactor
This commit is contained in:
parent
9a3fe4dd1e
commit
2ba18d2f05
@ -20,6 +20,7 @@ import { FormattedNumber } from 'components/FormattedNumber'
|
|||||||
import { SortAsc, SortDesc, SortNone } from 'components/Icons'
|
import { SortAsc, SortDesc, SortNone } from 'components/Icons'
|
||||||
import Text from 'components/Text'
|
import Text from 'components/Text'
|
||||||
import { ASSETS } from 'constants/assets'
|
import { ASSETS } from 'constants/assets'
|
||||||
|
import { MAX_AMOUNT_DECIMALS, MIN_AMOUNT } from 'constants/math'
|
||||||
import { ORACLE_DENOM } from 'constants/oracle'
|
import { ORACLE_DENOM } from 'constants/oracle'
|
||||||
import useCurrentAccount from 'hooks/useCurrentAccount'
|
import useCurrentAccount from 'hooks/useCurrentAccount'
|
||||||
import useMarketAssets from 'hooks/useMarketAssets'
|
import useMarketAssets from 'hooks/useMarketAssets'
|
||||||
@ -99,23 +100,24 @@ export default function Index(props: Props) {
|
|||||||
row.original.amount,
|
row.original.amount,
|
||||||
getAssetByDenom(row.original.denom) ?? ASSETS[0],
|
getAssetByDenom(row.original.denom) ?? ASSETS[0],
|
||||||
)
|
)
|
||||||
if (amount >= 0.01)
|
if (amount >= 1)
|
||||||
return (
|
return (
|
||||||
<FormattedNumber
|
<FormattedNumber
|
||||||
className={className}
|
className={className}
|
||||||
amount={amount}
|
amount={amount}
|
||||||
options={{ abbreviated: true }}
|
options={{ abbreviated: true, maxDecimals: MAX_AMOUNT_DECIMALS }}
|
||||||
animate
|
animate
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
||||||
const formattedAmount = formatAmountToPrecision(amount, 1)
|
const formattedAmount = formatAmountToPrecision(amount, MAX_AMOUNT_DECIMALS)
|
||||||
return (
|
return (
|
||||||
<FormattedNumber
|
<FormattedNumber
|
||||||
className={className}
|
className={className}
|
||||||
amount={formattedAmount}
|
smallerThanThreshold={formattedAmount < MIN_AMOUNT}
|
||||||
|
amount={formattedAmount < MIN_AMOUNT ? MIN_AMOUNT : formattedAmount}
|
||||||
options={{
|
options={{
|
||||||
maxDecimals: baseCurrency.decimals,
|
maxDecimals: MAX_AMOUNT_DECIMALS,
|
||||||
minDecimals: 0,
|
minDecimals: 0,
|
||||||
}}
|
}}
|
||||||
animate
|
animate
|
||||||
|
@ -6,7 +6,7 @@ import DisplayCurrency from 'components/DisplayCurrency'
|
|||||||
import { FormattedNumber } from 'components/FormattedNumber'
|
import { FormattedNumber } from 'components/FormattedNumber'
|
||||||
import { ArrowRight } from 'components/Icons'
|
import { ArrowRight } from 'components/Icons'
|
||||||
import Text from 'components/Text'
|
import Text from 'components/Text'
|
||||||
import { BN_ZERO } from 'constants/math'
|
import { BN_ZERO, MAX_AMOUNT_DECIMALS } from 'constants/math'
|
||||||
import { ORACLE_DENOM } from 'constants/oracle'
|
import { ORACLE_DENOM } from 'constants/oracle'
|
||||||
import useBorrowMarketAssetsTableData from 'hooks/useBorrowMarketAssetsTableData'
|
import useBorrowMarketAssetsTableData from 'hooks/useBorrowMarketAssetsTableData'
|
||||||
import useLendingMarketAssetsTableData from 'hooks/useLendingMarketAssetsTableData'
|
import useLendingMarketAssetsTableData from 'hooks/useLendingMarketAssetsTableData'
|
||||||
@ -134,7 +134,7 @@ function Item(props: ItemProps) {
|
|||||||
{props.isPercentage ? (
|
{props.isPercentage ? (
|
||||||
<FormattedNumber
|
<FormattedNumber
|
||||||
amount={current.toNumber()}
|
amount={current.toNumber()}
|
||||||
options={{ suffix: '%', minDecimals: 2, maxDecimals: 2 }}
|
options={{ suffix: '%', minDecimals: 2, maxDecimals: MAX_AMOUNT_DECIMALS }}
|
||||||
className='text-sm'
|
className='text-sm'
|
||||||
animate
|
animate
|
||||||
/>
|
/>
|
||||||
@ -152,7 +152,7 @@ function Item(props: ItemProps) {
|
|||||||
{props.isPercentage ? (
|
{props.isPercentage ? (
|
||||||
<FormattedNumber
|
<FormattedNumber
|
||||||
amount={change.toNumber()}
|
amount={change.toNumber()}
|
||||||
options={{ suffix: '%', minDecimals: 2, maxDecimals: 2 }}
|
options={{ suffix: '%', minDecimals: 2, maxDecimals: MAX_AMOUNT_DECIMALS }}
|
||||||
className={classNames('text-sm', increase ? 'text-profit' : 'text-loss')}
|
className={classNames('text-sm', increase ? 'text-profit' : 'text-loss')}
|
||||||
animate
|
animate
|
||||||
/>
|
/>
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import DisplayCurrency from 'components/DisplayCurrency'
|
import DisplayCurrency from 'components/DisplayCurrency'
|
||||||
import { FormattedNumber } from 'components/FormattedNumber'
|
import { FormattedNumber } from 'components/FormattedNumber'
|
||||||
|
import { MAX_AMOUNT_DECIMALS, MIN_AMOUNT } from 'constants/math'
|
||||||
import { BNCoin } from 'types/classes/BNCoin'
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
|
import { demagnify } from 'utils/formatters'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
asset: Asset
|
asset: Asset
|
||||||
@ -8,11 +10,13 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function AmountAndValue(props: Props) {
|
export default function AmountAndValue(props: Props) {
|
||||||
|
const amount = demagnify(props.amount.toString(), props.asset)
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-col gap-[0.5] text-xs'>
|
<div className='flex flex-col gap-[0.5] text-xs'>
|
||||||
<FormattedNumber
|
<FormattedNumber
|
||||||
amount={props.amount.toNumber()}
|
amount={amount < MIN_AMOUNT ? MIN_AMOUNT : amount}
|
||||||
options={{ decimals: props.asset.decimals, abbreviated: true }}
|
smallerThanThreshold={amount < MIN_AMOUNT}
|
||||||
|
options={{ abbreviated: true, maxDecimals: MAX_AMOUNT_DECIMALS }}
|
||||||
animate
|
animate
|
||||||
/>
|
/>
|
||||||
<DisplayCurrency
|
<DisplayCurrency
|
||||||
|
@ -4,13 +4,13 @@ import { useMemo } from 'react'
|
|||||||
import { FormattedNumber } from 'components/FormattedNumber'
|
import { FormattedNumber } from 'components/FormattedNumber'
|
||||||
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
||||||
import { DISPLAY_CURRENCY_KEY } from 'constants/localStore'
|
import { DISPLAY_CURRENCY_KEY } from 'constants/localStore'
|
||||||
|
import { ORACLE_DENOM } from 'constants/oracle'
|
||||||
import useLocalStorage from 'hooks/useLocalStorage'
|
import useLocalStorage from 'hooks/useLocalStorage'
|
||||||
import usePrices from 'hooks/usePrices'
|
import usePrices from 'hooks/usePrices'
|
||||||
import { BNCoin } from 'types/classes/BNCoin'
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
import { getDisplayCurrencies } from 'utils/assets'
|
import { getDisplayCurrencies } from 'utils/assets'
|
||||||
import { getCoinValue } from 'utils/formatters'
|
import { getCoinValue } from 'utils/formatters'
|
||||||
import { BN } from 'utils/helpers'
|
import { BN } from 'utils/helpers'
|
||||||
import { ORACLE_DENOM } from 'constants/oracle'
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
coin: BNCoin
|
coin: BNCoin
|
||||||
@ -34,12 +34,6 @@ export default function DisplayCurrency(props: Props) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
const isUSD = displayCurrencyAsset.id === 'USD'
|
const isUSD = displayCurrencyAsset.id === 'USD'
|
||||||
const prefix = isUSD
|
|
||||||
? `${props.isApproximation ? '~ ' : ''}$`
|
|
||||||
: `${props.isApproximation ? '~ ' : ''}`
|
|
||||||
const suffix = isUSD
|
|
||||||
? ''
|
|
||||||
: ` ${displayCurrencyAsset.symbol ? ` ${displayCurrencyAsset.symbol}` : ''}`
|
|
||||||
|
|
||||||
const amount = useMemo(() => {
|
const amount = useMemo(() => {
|
||||||
const coinValue = getCoinValue(props.coin, prices)
|
const coinValue = getCoinValue(props.coin, prices)
|
||||||
@ -55,13 +49,23 @@ export default function DisplayCurrency(props: Props) {
|
|||||||
return coinValue.div(displayPrice).toNumber()
|
return coinValue.div(displayPrice).toNumber()
|
||||||
}, [displayCurrency, displayCurrencyAsset.decimals, prices, props.coin])
|
}, [displayCurrency, displayCurrencyAsset.decimals, prices, props.coin])
|
||||||
|
|
||||||
|
const isLessThanACent = isUSD && amount < 0.01 && amount > 0
|
||||||
|
const smallerThanPrefix = isLessThanACent ? '< ' : ''
|
||||||
|
|
||||||
|
const prefix = isUSD
|
||||||
|
? `${props.isApproximation ? '~ ' : smallerThanPrefix}$`
|
||||||
|
: `${props.isApproximation ? '~ ' : ''}`
|
||||||
|
const suffix = isUSD
|
||||||
|
? ''
|
||||||
|
: ` ${displayCurrencyAsset.symbol ? ` ${displayCurrencyAsset.symbol}` : ''}`
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormattedNumber
|
<FormattedNumber
|
||||||
className={classNames(
|
className={classNames(
|
||||||
props.className,
|
props.className,
|
||||||
props.parentheses && 'before:content-["("] after:content-[")"]',
|
props.parentheses && 'before:content-["("] after:content-[")"]',
|
||||||
)}
|
)}
|
||||||
amount={amount}
|
amount={isLessThanACent ? 0.01 : amount}
|
||||||
options={{
|
options={{
|
||||||
minDecimals: isUSD ? 2 : 0,
|
minDecimals: isUSD ? 2 : 0,
|
||||||
maxDecimals: 2,
|
maxDecimals: 2,
|
||||||
|
@ -13,6 +13,7 @@ interface Props {
|
|||||||
className?: string
|
className?: string
|
||||||
animate?: boolean
|
animate?: boolean
|
||||||
parentheses?: boolean
|
parentheses?: boolean
|
||||||
|
smallerThanThreshold?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FormattedNumber = React.memo(
|
export const FormattedNumber = React.memo(
|
||||||
@ -23,6 +24,15 @@ export const FormattedNumber = React.memo(
|
|||||||
)
|
)
|
||||||
const prevAmountRef = useRef<number>(0)
|
const prevAmountRef = useRef<number>(0)
|
||||||
|
|
||||||
|
let { options, smallerThanThreshold } = props
|
||||||
|
|
||||||
|
if (smallerThanThreshold) {
|
||||||
|
if (!options) options = { prefix: '< ' }
|
||||||
|
if (options.prefix && options.prefix.substring(0, 1) !== '<')
|
||||||
|
options.prefix = `< ${options.prefix}`
|
||||||
|
else options.prefix = '< '
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (prevAmountRef.current !== props.amount) prevAmountRef.current = props.amount
|
if (prevAmountRef.current !== props.amount) prevAmountRef.current = props.amount
|
||||||
}, [props.amount])
|
}, [props.amount])
|
||||||
@ -47,7 +57,7 @@ export const FormattedNumber = React.memo(
|
|||||||
props.className,
|
props.className,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{formatValue(props.amount.toString(), props.options)}
|
{formatValue(props.amount.toString(), options)}
|
||||||
</p>
|
</p>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ import { Heart } from 'components/Icons'
|
|||||||
import Loading from 'components/Loading'
|
import Loading from 'components/Loading'
|
||||||
import Text from 'components/Text'
|
import Text from 'components/Text'
|
||||||
import TitleAndSubCell from 'components/TitleAndSubCell'
|
import TitleAndSubCell from 'components/TitleAndSubCell'
|
||||||
|
import { MAX_AMOUNT_DECIMALS } from 'constants/math'
|
||||||
import { ORACLE_DENOM } from 'constants/oracle'
|
import { ORACLE_DENOM } from 'constants/oracle'
|
||||||
import useAccount from 'hooks/useAccount'
|
import useAccount from 'hooks/useAccount'
|
||||||
import useBorrowMarketAssetsTableData from 'hooks/useBorrowMarketAssetsTableData'
|
import useBorrowMarketAssetsTableData from 'hooks/useBorrowMarketAssetsTableData'
|
||||||
@ -70,7 +71,11 @@ function Content(props: Props) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: (
|
title: (
|
||||||
<FormattedNumber className='text-xl' amount={apr.toNumber()} options={{ suffix: '%' }} />
|
<FormattedNumber
|
||||||
|
className='text-xl'
|
||||||
|
amount={apr.toNumber()}
|
||||||
|
options={{ suffix: '%', maxDecimals: MAX_AMOUNT_DECIMALS, minDecimals: 2 }}
|
||||||
|
/>
|
||||||
),
|
),
|
||||||
sub: STATS[3].sub,
|
sub: STATS[3].sub,
|
||||||
},
|
},
|
||||||
@ -105,7 +110,7 @@ interface SkeletonProps extends Props {
|
|||||||
|
|
||||||
function Skeleton(props: SkeletonProps) {
|
function Skeleton(props: SkeletonProps) {
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-col py-8 gap-8'>
|
<div className='flex flex-col gap-8 py-8'>
|
||||||
<div className='flex justify-between'>
|
<div className='flex justify-between'>
|
||||||
<Text size='2xl'>Credit Account {props.accountId}</Text>
|
<Text size='2xl'>Credit Account {props.accountId}</Text>
|
||||||
<div className='flex gap-1 max-w-[300px] flex-grow'>
|
<div className='flex gap-1 max-w-[300px] flex-grow'>
|
||||||
@ -115,7 +120,7 @@ function Skeleton(props: SkeletonProps) {
|
|||||||
</div>
|
</div>
|
||||||
<div className='grid grid-cols-2 gap-4 lg:grid-cols-5 md:grid-cols-4 sm:grid-cols-3'>
|
<div className='grid grid-cols-2 gap-4 lg:grid-cols-5 md:grid-cols-4 sm:grid-cols-3'>
|
||||||
{props.stats.map((stat) => (
|
{props.stats.map((stat) => (
|
||||||
<Card key={stat.sub} className='p-6 bg-white/5 flex-grow-1 text-center'>
|
<Card key={stat.sub} className='p-6 text-center bg-white/5 flex-grow-1'>
|
||||||
<TitleAndSubCell
|
<TitleAndSubCell
|
||||||
title={stat.title || <Loading className='w-20 h-6 mx-auto mb-2' />}
|
title={stat.title || <Loading className='w-20 h-6 mx-auto mb-2' />}
|
||||||
sub={stat.sub}
|
sub={stat.sub}
|
||||||
|
@ -12,7 +12,7 @@ import { AvailableOrderType } from 'components/Trade/TradeModule/SwapForm/OrderT
|
|||||||
import TradeSummary from 'components/Trade/TradeModule/SwapForm/TradeSummary'
|
import TradeSummary from 'components/Trade/TradeModule/SwapForm/TradeSummary'
|
||||||
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
||||||
import { SLIPPAGE_KEY } from 'constants/localStore'
|
import { SLIPPAGE_KEY } from 'constants/localStore'
|
||||||
import { BN_ZERO } from 'constants/math'
|
import { BN_ZERO, MARGIN_TRADE_BUFFER } from 'constants/math'
|
||||||
import useAutoLend from 'hooks/useAutoLend'
|
import useAutoLend from 'hooks/useAutoLend'
|
||||||
import useCurrentAccount from 'hooks/useCurrentAccount'
|
import useCurrentAccount from 'hooks/useCurrentAccount'
|
||||||
import useHealthComputer from 'hooks/useHealthComputer'
|
import useHealthComputer from 'hooks/useHealthComputer'
|
||||||
@ -27,7 +27,7 @@ import { BNCoin } from 'types/classes/BNCoin'
|
|||||||
import { byDenom } from 'utils/array'
|
import { byDenom } from 'utils/array'
|
||||||
import { defaultFee } from 'utils/constants'
|
import { defaultFee } from 'utils/constants'
|
||||||
import { getCapLeftWithBuffer } from 'utils/generic'
|
import { getCapLeftWithBuffer } from 'utils/generic'
|
||||||
import { asyncThrottle, BN } from 'utils/helpers'
|
import { BN, asyncThrottle } from 'utils/helpers'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
buyAsset: Asset
|
buyAsset: Asset
|
||||||
@ -108,6 +108,8 @@ export default function SwapForm(props: Props) {
|
|||||||
const [maxSellAmount, sellSideMarginThreshold, marginRatio] = useMemo(() => {
|
const [maxSellAmount, sellSideMarginThreshold, marginRatio] = useMemo(() => {
|
||||||
const maxAmount = computeMaxSwapAmount(sellAsset.denom, buyAsset.denom, 'default')
|
const maxAmount = computeMaxSwapAmount(sellAsset.denom, buyAsset.denom, 'default')
|
||||||
const maxAmountOnMargin = computeMaxSwapAmount(sellAsset.denom, buyAsset.denom, 'margin')
|
const maxAmountOnMargin = computeMaxSwapAmount(sellAsset.denom, buyAsset.denom, 'margin')
|
||||||
|
.multipliedBy(MARGIN_TRADE_BUFFER)
|
||||||
|
.integerValue()
|
||||||
const marginRatio = maxAmount.dividedBy(maxAmountOnMargin)
|
const marginRatio = maxAmount.dividedBy(maxAmountOnMargin)
|
||||||
|
|
||||||
estimateExactIn(
|
estimateExactIn(
|
||||||
|
@ -2,3 +2,7 @@ import { BN } from 'utils/helpers'
|
|||||||
|
|
||||||
export const BN_ZERO = BN(0)
|
export const BN_ZERO = BN(0)
|
||||||
export const BN_ONE = BN(1)
|
export const BN_ONE = BN(1)
|
||||||
|
|
||||||
|
export const MARGIN_TRADE_BUFFER = 0.9
|
||||||
|
export const MIN_AMOUNT = 0.000001
|
||||||
|
export const MAX_AMOUNT_DECIMALS = 6
|
||||||
|
Loading…
Reference in New Issue
Block a user