mango-v4-ui/components/trade/TradeSummary.tsx

261 lines
8.8 KiB
TypeScript
Raw Normal View History

2022-12-21 20:19:00 -08:00
import {
HealthType,
MangoAccount,
PerpMarket,
Serum3Market,
} from '@blockworks-foundation/mango-v4'
2023-01-24 16:54:24 -08:00
import FormatNumericValue from '@components/shared/FormatNumericValue'
2022-12-21 20:19:00 -08:00
import HealthImpact from '@components/shared/HealthImpact'
import Tooltip from '@components/shared/Tooltip'
import mangoStore from '@store/mangoStore'
2023-04-25 05:41:23 -07:00
import Decimal from 'decimal.js'
2022-12-21 20:19:00 -08:00
import useMangoGroup from 'hooks/useMangoGroup'
import useSelectedMarket from 'hooks/useSelectedMarket'
import { useTranslation } from 'next-i18next'
import { useMemo } from 'react'
import Slippage from './Slippage'
import {
floorToDecimal,
formatNumericValue,
// getDecimalCount,
} from 'utils/numbers'
import { formatTokenSymbol } from 'utils/tokens'
// import useOpenPerpPositions from 'hooks/useOpenPerpPositions'
2022-12-21 20:19:00 -08:00
const TradeSummary = ({
mangoAccount,
2023-03-17 05:48:38 -07:00
useMargin,
2022-12-21 20:19:00 -08:00
}: {
mangoAccount: MangoAccount | undefined
2023-03-17 05:48:38 -07:00
useMargin: boolean
2022-12-21 20:19:00 -08:00
}) => {
const { t } = useTranslation(['common', 'trade'])
const { group } = useMangoGroup()
const tradeForm = mangoStore((s) => s.tradeForm)
2023-04-25 05:41:23 -07:00
const { selectedMarket, quoteBank } = useSelectedMarket()
// const openPerpPositions = useOpenPerpPositions()
// this isn't correct yet
// const avgEntryPrice = useMemo(() => {
// if (
// !openPerpPositions.length ||
// !selectedMarket ||
// selectedMarket instanceof Serum3Market
// )
// return
// const openPosition = openPerpPositions.find(
// (pos) => pos.marketIndex === selectedMarket.perpMarketIndex
// )
// if (openPosition && tradeForm.price) {
// const currentAvgPrice =
// openPosition.getAverageEntryPriceUi(selectedMarket)
// const newAvgPrice = (currentAvgPrice + Number(tradeForm.price)) / 2
// return newAvgPrice
// }
// return
// }, [openPerpPositions, selectedMarket, tradeForm])
2022-12-21 20:19:00 -08:00
const maintProjectedHealth = useMemo(() => {
2023-03-04 10:53:49 -08:00
if (!mangoAccount || !group) return 100
2022-12-21 20:19:00 -08:00
let simulatedHealthRatio = 0
try {
if (selectedMarket instanceof Serum3Market) {
simulatedHealthRatio =
tradeForm.side === 'sell'
? mangoAccount.simHealthRatioWithSerum3AskUiChanges(
group,
Number(tradeForm.baseSize),
selectedMarket.serumMarketExternal,
HealthType.maint
)
: mangoAccount.simHealthRatioWithSerum3BidUiChanges(
group,
Number(tradeForm.quoteSize),
selectedMarket.serumMarketExternal,
HealthType.maint
)
} else if (selectedMarket instanceof PerpMarket) {
simulatedHealthRatio =
tradeForm.side === 'sell'
? mangoAccount.simHealthRatioWithPerpAskUiChanges(
group,
selectedMarket.perpMarketIndex,
parseFloat(tradeForm.baseSize) || 0
2022-12-21 20:19:00 -08:00
)
: mangoAccount.simHealthRatioWithPerpBidUiChanges(
group,
selectedMarket.perpMarketIndex,
parseFloat(tradeForm.baseSize) || 0
2022-12-21 20:19:00 -08:00
)
}
} catch (e) {
console.warn('Error calculating projected health: ', e)
}
return simulatedHealthRatio > 100
? 100
: simulatedHealthRatio < 0
? 0
: Math.trunc(simulatedHealthRatio)
2023-01-02 11:50:09 -08:00
}, [group, mangoAccount, selectedMarket, tradeForm])
2022-12-21 20:19:00 -08:00
2023-03-17 05:48:38 -07:00
const balanceBank = useMemo(() => {
if (
!group ||
!selectedMarket ||
selectedMarket instanceof PerpMarket ||
!useMargin
)
return
if (tradeForm.side === 'buy') {
return group.getFirstBankByTokenIndex(selectedMarket.quoteTokenIndex)
} else {
return group.getFirstBankByTokenIndex(selectedMarket.baseTokenIndex)
}
}, [group, selectedMarket, tradeForm.side])
const [balance, borrowAmount] = useMemo(() => {
if (!balanceBank || !mangoAccount) return [0, 0]
2023-03-17 05:48:38 -07:00
let borrowAmount
const balance = mangoAccount.getTokenDepositsUi(balanceBank)
if (tradeForm.side === 'buy') {
const remainingBalance = balance - parseFloat(tradeForm.quoteSize)
borrowAmount = remainingBalance < 0 ? Math.abs(remainingBalance) : 0
} else {
const remainingBalance = balance - parseFloat(tradeForm.baseSize)
borrowAmount = remainingBalance < 0 ? Math.abs(remainingBalance) : 0
}
return [balance, borrowAmount]
2023-03-17 05:48:38 -07:00
}, [balanceBank, mangoAccount, tradeForm])
2023-04-25 05:41:23 -07:00
const orderValue = useMemo(() => {
2023-04-28 11:39:22 -07:00
if (
!quoteBank ||
!tradeForm.price ||
2023-05-13 04:41:42 -07:00
!tradeForm.baseSize ||
2023-06-15 05:32:40 -07:00
isNaN(parseFloat(tradeForm.price)) ||
isNaN(parseFloat(tradeForm.baseSize))
2023-04-28 11:39:22 -07:00
)
return 0
2023-04-25 05:41:23 -07:00
const basePriceDecimal = new Decimal(tradeForm.price)
const quotePriceDecimal = new Decimal(quoteBank.uiPrice)
const sizeDecimal = new Decimal(tradeForm.baseSize)
2023-05-13 04:41:42 -07:00
return floorToDecimal(
basePriceDecimal.mul(quotePriceDecimal).mul(sizeDecimal),
2
)
2023-04-25 05:41:23 -07:00
}, [quoteBank, tradeForm])
2022-12-21 20:19:00 -08:00
return (
<div className="space-y-2 px-3 md:px-4">
2022-12-30 10:26:45 -08:00
<div className="flex justify-between text-xs">
<p>{t('trade:order-value')}</p>
<p className="text-th-fgd-2">
2023-05-13 04:41:42 -07:00
{orderValue ? <FormatNumericValue value={orderValue} isUsd /> : ''}
2022-12-30 10:26:45 -08:00
</p>
</div>
2022-12-21 20:19:00 -08:00
<HealthImpact maintProjectedHealth={maintProjectedHealth} small />
{borrowAmount && balanceBank ? (
<>
<div className="flex justify-between text-xs">
<Tooltip
content={
balance
? t('trade:tooltip-borrow-balance', {
balance: formatNumericValue(balance),
borrowAmount: formatNumericValue(borrowAmount),
token: formatTokenSymbol(balanceBank.name),
rate: formatNumericValue(
balanceBank.getBorrowRateUi(),
2
),
})
: t('trade:tooltip-borrow-no-balance', {
borrowAmount: formatNumericValue(borrowAmount),
token: formatTokenSymbol(balanceBank.name),
rate: formatNumericValue(
balanceBank.getBorrowRateUi(),
2
),
})
2023-03-17 05:48:38 -07:00
}
delay={100}
>
<p className="tooltip-underline">{t('borrow-amount')}</p>
</Tooltip>
<p className="text-right font-mono text-th-fgd-2">
<FormatNumericValue
value={borrowAmount}
decimals={balanceBank.mintDecimals}
/>{' '}
<span className="font-body text-th-fgd-4">
{formatTokenSymbol(balanceBank.name)}
</span>
</p>
</div>
<div className="flex justify-between text-xs">
<Tooltip
content={t('loan-origination-fee-tooltip', {
fee: `${(
balanceBank.loanOriginationFeeRate.toNumber() * 100
).toFixed(3)}%`,
})}
delay={100}
>
<p className="tooltip-underline">{t('loan-origination-fee')}</p>
</Tooltip>
<p className="text-right font-mono text-th-fgd-2">
<FormatNumericValue
value={
borrowAmount * balanceBank.loanOriginationFeeRate.toNumber()
}
decimals={balanceBank.mintDecimals}
/>{' '}
<span className="font-body text-th-fgd-4">
{formatTokenSymbol(balanceBank.name)}
</span>
</p>
</div>
</>
2023-03-17 05:48:38 -07:00
) : null}
{/* <div className="flex justify-between text-xs">
2022-12-21 20:19:00 -08:00
<Tooltip content="The amount of capital you have to use for trades and loans. When your free collateral reaches $0 you won't be able to trade, borrow or withdraw.">
<p className="tooltip-underline">{t('free-collateral')}</p>
</Tooltip>
<p className="text-th-fgd-2">
2023-01-24 16:54:24 -08:00
{group && mangoAccount ? (
<FormatNumericValue
value={toUiDecimalsForQuote(
mangoAccount.getCollateralValue(group)
)}
decimals={2}
isUsd
/>
) : (
''
)}
2022-12-21 20:19:00 -08:00
</p>
</div> */}
2022-12-21 20:19:00 -08:00
<Slippage />
{/* {avgEntryPrice && selectedMarket instanceof PerpMarket ? (
<div className="flex justify-between text-xs">
<p>{t('trade:avg-entry-price')}</p>
<p className="text-th-fgd-2">
{tradeForm.tradeType === 'Market' ? '~' : ''}
<FormatNumericValue
value={avgEntryPrice}
decimals={getDecimalCount(selectedMarket.tickSize)}
isUsd
/>
</p>
</div>
) : null} */}
2022-12-21 20:19:00 -08:00
</div>
)
}
export default TradeSummary