warnings and layout fixes

This commit is contained in:
saml33 2024-03-27 12:49:18 +11:00
parent 69a32541a6
commit 82925628c7
5 changed files with 598 additions and 365 deletions

View File

@ -333,11 +333,7 @@ const DashboardSuggestedValues = ({
)
return (
<Modal
panelClassNames={' !max-w-[800px]'}
isOpen={isOpen}
onClose={onClose}
>
<Modal panelClassNames="!max-w-[800px]" isOpen={isOpen} onClose={onClose}>
<h3 className="mb-6">
<span>
{bank.name} - Suggested tier: {PRESETS[suggestedTierKey].preset_name}{' '}
@ -368,7 +364,7 @@ const DashboardSuggestedValues = ({
))}
</Select>
</h3>
<div className="flex max-h-[600px] w-full flex-col overflow-auto">
<div className="flex w-full flex-col">
<div className="p-4">
<div className="mb-2">
<Label text="Oracle pk (Leave empty if no change)" />

View File

@ -50,7 +50,7 @@ function Modal({
aria-hidden="true"
/>
<div
className={`fixed inset-0 flex items-center sm:justify-center ${
className={`fixed inset-0 flex items-center sm:justify-center ${
fullScreen ? '' : 'sm:px-4'
}`}
>
@ -59,10 +59,10 @@ function Modal({
themeData.fonts.display.variable
} ${
themeData.fonts.mono.variable
} h-full w-full bg-th-bkg-1 font-body ${
} thin-scroll h-full max-h-[calc(100vh-5%)] w-full overflow-auto bg-th-bkg-1 font-body ${
fullScreen
? ''
: 'p-4 sm:h-auto sm:max-w-md sm:rounded-lg sm:border sm:border-th-bkg-3 sm:p-6'
: 'p-4 sm:max-w-md sm:rounded-lg sm:border sm:border-th-bkg-3 sm:p-6'
} relative ${panelClassNames}`}
>
<div>{children}</div>

View File

@ -4,6 +4,7 @@ import {
I80F48,
PriceImpact,
OracleProvider,
toUiDecimalsForQuote,
} from '@blockworks-foundation/mango-v4'
import ExplorerLink from '@components/shared/ExplorerLink'
import { coder } from '@project-serum/anchor/dist/cjs/spl/token'
@ -15,6 +16,7 @@ import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
import {
ArrowTopRightOnSquareIcon,
ChevronDownIcon,
ExclamationTriangleIcon,
} from '@heroicons/react/20/solid'
import { Disclosure } from '@headlessui/react'
import MarketLogos from '@components/trade/MarketLogos'
@ -43,9 +45,14 @@ import {
getMidPriceImpacts,
getProposedKey,
} from '@blockworks-foundation/mango-v4-settings/lib/helpers/listingTools'
import Tooltip from '@components/shared/Tooltip'
dayjs.extend(relativeTime)
type BanksWarningObject = {
[key: string]: Record<string, string>
}
export async function getStaticProps({ locale }: { locale: string }) {
return {
props: {
@ -168,6 +175,82 @@ const Dashboard: NextPage = () => {
}
}, [banks.length])
const warningBanks: BanksWarningObject | undefined = useMemo(() => {
if (!banks?.length) return
const warnings = banks.reduce((acc: BanksWarningObject, bank) => {
acc[bank.name] = {}
return acc
}, {})
for (const bank of banks) {
const deposits = toUiDecimals(
bank.indexedDeposits.mul(bank.depositIndex).toNumber(),
bank.mintDecimals,
)
const depositLimit = toUiDecimals(bank.depositLimit, bank.mintDecimals)
const depositsValue = deposits * bank.uiPrice
const depositsScaleStart = toUiDecimalsForQuote(
bank.depositWeightScaleStartQuote,
)
const netBorrowsInWindow = toUiDecimalsForQuote(
I80F48.fromI64(bank.netBorrowsInWindow).mul(bank.price),
)
const netBorrowLimitPerWindowQuote = toUiDecimals(
bank.netBorrowLimitPerWindowQuote,
6,
)
const borrowsValue =
toUiDecimals(
bank.indexedBorrows.mul(bank.borrowIndex).toNumber(),
bank.mintDecimals,
) * bank.uiPrice
const borrowsScaleStart = toUiDecimalsForQuote(
bank.borrowWeightScaleStartQuote,
)
const oracleConfFilter = 100 * bank.oracleConfig.confFilter.toNumber()
const lastKnownConfidence =
bank._oracleLastKnownDeviation instanceof I80F48 &&
!bank._oracleLastKnownDeviation.isZero()
? bank._oracleLastKnownDeviation
?.div(bank.price)
.mul(I80F48.fromNumber(100))
.toNumber()
: 0
if (depositsValue > depositsScaleStart) {
warnings[bank.name].depositWeightScaleStartQuote =
'Deposits value exceeds scaling start quote'
}
if (borrowsValue > borrowsScaleStart) {
warnings[bank.name].borrowWeightScaleStartQuote =
'Borrows value exceeds scaling start quote'
}
if (deposits >= depositLimit) {
warnings[bank.name].depositLimit = 'Deposits are at capacity'
}
if (netBorrowsInWindow >= netBorrowLimitPerWindowQuote) {
warnings[bank.name].netBorrowLimitPerWindowQuote =
'Net borrows in current window are at capacity'
}
if (lastKnownConfidence && lastKnownConfidence > oracleConfFilter) {
warnings[
bank.name
].oracleConfFilter = `Oracle confidence is outside the limit. Current: ${lastKnownConfidence.toFixed(
2,
)}% limit: ${oracleConfFilter.toFixed(2)}%`
}
}
return warnings
}, [banks])
const sortByTier = (tier: string | undefined) => {
const tierOrder: Record<string, number> = {
AAA: 0,
@ -186,11 +269,11 @@ const Dashboard: NextPage = () => {
}
return (
<GovernancePageWrapper noStyles={true}>
<div className="col-span-12 lg:col-span-8 lg:col-start-3">
<DashboardNavbar />
<>
<DashboardNavbar />
<GovernancePageWrapper>
{group ? (
<div className="ml-80 mr-80 mt-4">
<div className="mx-4 mt-4 lg:mx-0">
<ExplorerLink
address={group?.publicKey.toString()}
anchorData
@ -205,11 +288,26 @@ const Dashboard: NextPage = () => {
'[aria-expanded=false][aria-label=panel]',
),
]
console.log(panels)
panels.map((panel) => (panel as HTMLElement).click())
}}
>
Expand All
</Button>
<Button
secondary
size="small"
onClick={() => {
const panels = [
...document.querySelectorAll(
'[aria-expanded=false][aria-label=panel].has-warning',
),
]
panels.map((panel) => (panel as HTMLElement).click())
}}
>
Expand Warnings
</Button>
<Button
secondary
size="small"
@ -227,7 +325,7 @@ const Dashboard: NextPage = () => {
</div>
<h3 className="mb-3 mt-6 flex text-base text-th-fgd-3">
<span>Banks</span>
<span className="ml-auto">
<span className="ml-auto pr-12 text-sm font-normal">
Current / <span className="text-th-success">Suggested</span>{' '}
</span>
</h3>
@ -254,29 +352,95 @@ const Dashboard: NextPage = () => {
const { currentTier, suggestedTierKey } =
getSuggestedAndCurrentTier(bank)
const depositLimitWarning =
warningBanks?.[bank.name]?.depositLimit ?? null
const depositWeightScaleStartQuoteWarning =
warningBanks?.[bank.name]?.depositWeightScaleStartQuote ??
null
const depositWarnings = [
depositLimitWarning,
depositWeightScaleStartQuoteWarning,
].filter(Boolean)
const borrowWeightScaleStartQuoteWarning =
warningBanks?.[bank.name]?.borrowWeightScaleStartQuote ??
null
const netBorrowLimitPerWindowQuoteWarning =
warningBanks?.[bank.name]?.netBorrowLimitPerWindowQuote ??
null
const borrowWarnings = [
borrowWeightScaleStartQuoteWarning,
netBorrowLimitPerWindowQuoteWarning,
].filter(Boolean)
const oracleConfFilterWarning =
warningBanks?.[bank.name]?.oracleConfFilter ?? null
const oracleWarnings = [oracleConfFilterWarning].filter(
Boolean,
)
const showWarningTooltip =
warningBanks && Object.keys(warningBanks[bank.name]).length
return (
<Disclosure key={bank.publicKey.toString()}>
{({ open }) => (
<>
<div
className={`w-full border-t border-th-bkg-3 p-4 md:hover:bg-th-bkg-4 ${
className={`default-transition w-full border-t border-th-bkg-3 md:hover:bg-th-bkg-2 ${
open
? i === stickyIndex
? 'sticky top-0 bg-th-bkg-4'
: 'bg-th-bkg-4'
? 'sticky top-0 bg-th-bkg-3'
: 'bg-th-bkg-3'
: ''
}`}
id={`parent-item-${i}`}
>
<Disclosure.Button
className="flex w-full items-center justify-between"
className={`flex w-full items-center justify-between p-4 ${
showWarningTooltip ? 'has-warning' : ''
}`}
aria-label="panel"
>
<div className="flex items-center">
<TokenLogo bank={bank} />
<p className="ml-2 text-th-fgd-2">
{formattedBankValues.name} Bank
</p>
<Tooltip
content={
showWarningTooltip ? (
<div className="space-y-1.5">
{Object.values(
warningBanks[bank.name],
).map((value, index) => (
<p key={value}>
{index + 1}. {value}
</p>
))}
</div>
) : (
''
)
}
>
<div className="flex items-center">
<p
className={`ml-2 ${
showWarningTooltip
? 'tooltip-underline text-th-warning'
: 'text-th-fgd-2'
}`}
>
{formattedBankValues.name} Bank
</p>
{showWarningTooltip ? (
<ExclamationTriangleIcon className="ml-2 h-4 w-4 cursor-help text-th-warning" />
) : null}
</div>
</Tooltip>
</div>
<div className="flex items-center space-x-3">
<div className="flex space-x-2">
@ -298,6 +462,38 @@ const Dashboard: NextPage = () => {
</Disclosure.Button>
</div>
<Disclosure.Panel>
{bank.mint.toBase58() !== USDC_MINT ? (
<div className="my-3 flex">
<Button
className="ml-auto"
onClick={() =>
setOpenedSuggestedModal(
bank.mint.toBase58(),
)
}
size="small"
>
Check suggested values
{openedSuggestedModal ===
bank.mint.toBase58() && (
<DashboardSuggestedValues
midPriceImp={midPriceImp}
currentTier={currentTier}
suggestedTierKey={suggestedTierKey}
group={group}
bank={bank}
isOpen={
openedSuggestedModal ===
bank.mint.toBase58()
}
onClose={() =>
setOpenedSuggestedModal(null)
}
></DashboardSuggestedValues>
)}
</Button>
</div>
) : null}
<KeyValuePair
label="Mint"
value={
@ -434,10 +630,12 @@ const Dashboard: NextPage = () => {
<KeyValuePair
label="Deposits"
value={`${formattedBankValues.deposits} ($${formattedBankValues.depositsPrice})`}
warnings={depositWarnings}
/>
<KeyValuePair
label="Borrows"
value={`${formattedBankValues.borrows} ($${formattedBankValues.borrowsPrice})`}
warnings={borrowWarnings}
/>
<KeyValuePair
label="Deposit weight scale start quote"
@ -509,6 +707,7 @@ const Dashboard: NextPage = () => {
.toFixed(2)
: 'null'
}%)`}
warnings={oracleWarnings}
/>
<KeyValuePair
label="Oracle: Max Staleness"
@ -563,37 +762,6 @@ const Dashboard: NextPage = () => {
formattedBankValues.maintWeightShiftDurationInv
}
/>
{bank.mint.toBase58() !== USDC_MINT && (
<div className="mb-4 mt-2 flex">
<Button
className=" ml-auto"
onClick={() =>
setOpenedSuggestedModal(
bank.mint.toBase58(),
)
}
>
Check suggested values
{openedSuggestedModal ===
bank.mint.toBase58() && (
<DashboardSuggestedValues
midPriceImp={midPriceImp}
currentTier={currentTier}
suggestedTierKey={suggestedTierKey}
group={group}
bank={bank}
isOpen={
openedSuggestedModal ===
bank.mint.toBase58()
}
onClose={() =>
setOpenedSuggestedModal(null)
}
></DashboardSuggestedValues>
)}
</Button>
</div>
)}
</Disclosure.Panel>
</>
)}
@ -996,23 +1164,52 @@ const Dashboard: NextPage = () => {
) : (
'Loading'
)}
</div>
</GovernancePageWrapper>
</GovernancePageWrapper>
</>
)
}
const KeyValuePair = ({
label,
value,
warnings,
}: {
label: string
value: number | ReactNode | string
warnings?: (string | null)[]
}) => {
return (
<div className="flex items-center justify-between border-t border-th-bkg-2 px-6 py-3 md:hover:bg-th-bkg-2">
<span className="mr-4 flex flex-col whitespace-nowrap text-th-fgd-3">
{label}
</span>
<Tooltip
content={
warnings?.length ? (
<div className="space-y-1.5">
{warnings.map((value, index) => (
<p key={value}>
{index + 1}. {value}
</p>
))}
</div>
) : (
''
)
}
>
<div className="flex items-center">
<span
className={`mr-4 flex flex-col whitespace-nowrap ${
warnings?.length
? 'tooltip-underline text-th-warning'
: 'text-th-fgd-3'
}`}
>
{label}
</span>
{warnings?.length ? (
<ExclamationTriangleIcon className="h-4 w-4 cursor-help text-th-warning" />
) : null}
</div>
</Tooltip>
<span className="flex flex-col font-mono text-th-fgd-2">
<div>
<span>{value}</span>

View File

@ -70,325 +70,363 @@ const MangoAccountDashboard: NextPage = () => {
}, [mangoAccount, loadOpenOrders])
return (
<div className="col-span-12 lg:col-span-8 lg:col-start-3">
<>
<DashboardNavbar />
<div className="ml-80 mr-80">
<div className="mt-4 flex space-x-2">
<Input
type="text"
name="search"
id="search"
value={searchString}
onChange={(e: ChangeEvent<HTMLInputElement>) =>
setSearchString(e.target.value)
}
/>
<Button
className="flex items-center"
onClick={() => {
const encodedSearchString = encodeURIComponent(searchString)
router.push(
`/dashboard/mangoaccount?address=${encodedSearchString}`,
)
}}
disabled={!searchString}
size="large"
>
<MagnifyingGlassIcon className="mr-2 h-5 w-5" />
Search
</Button>
</div>
</div>
{group && mangoAccount ? (
<div className="ml-80 mr-80 mt-4">
<h2 className="mb-6">Mango Account</h2>
<div className="grid grid-cols-12">
<div className="col-span-12 lg:col-span-8 lg:col-start-3">
<div className="mx-4 mt-4 lg:mx-0">
<div className="mt-4 flex space-x-2">
<Input
type="text"
name="search"
id="search"
value={searchString}
onChange={(e: ChangeEvent<HTMLInputElement>) =>
setSearchString(e.target.value)
}
/>
<Button
className="flex items-center"
onClick={() => {
const encodedSearchString = encodeURIComponent(searchString)
router.push(
`/dashboard/mangoaccount?address=${encodedSearchString}`,
)
}}
disabled={!searchString}
size="large"
>
<MagnifyingGlassIcon className="mr-2 h-5 w-5" />
Search
</Button>
</div>
</div>
{group && mangoAccount ? (
<div className="mx-4 mt-4 lg:mx-0">
<h2 className="mb-6">Mango Account</h2>
<KeyValuePair
label="Address"
value={<ExplorerLink address={mangoAccount.publicKey.toString()} />}
/>
<KeyValuePair
label="Owner"
value={<ExplorerLink address={mangoAccount.owner.toString()} />}
/>
<KeyValuePair label="Name" value={mangoAccount.name.toString()} />
<KeyValuePair
label="Delegate"
value={<ExplorerLink address={mangoAccount.delegate.toString()} />}
/>
<KeyValuePair
label="Account Number"
value={mangoAccount.accountNum.toString()}
/>
<KeyValuePair
label="Being Liquidated"
value={mangoAccount.beingLiquidated.toString()}
/>
<KeyValuePair
label="Init Health"
value={`$${toUiDecimalsForQuote(
mangoAccount.getHealth(group, HealthType.init),
).toFixed(4)}`}
/>
<KeyValuePair
label="Maint Health"
value={`$${toUiDecimalsForQuote(
mangoAccount.getHealth(group, HealthType.maint),
).toFixed(4)}`}
/>
{/* <KeyValuePair
<KeyValuePair
label="Address"
value={
<ExplorerLink address={mangoAccount.publicKey.toString()} />
}
/>
<KeyValuePair
label="Owner"
value={<ExplorerLink address={mangoAccount.owner.toString()} />}
/>
<KeyValuePair label="Name" value={mangoAccount.name.toString()} />
<KeyValuePair
label="Delegate"
value={
<ExplorerLink address={mangoAccount.delegate.toString()} />
}
/>
<KeyValuePair
label="Account Number"
value={mangoAccount.accountNum.toString()}
/>
<KeyValuePair
label="Being Liquidated"
value={mangoAccount.beingLiquidated.toString()}
/>
<KeyValuePair
label="Init Health"
value={`$${toUiDecimalsForQuote(
mangoAccount.getHealth(group, HealthType.init),
).toFixed(4)}`}
/>
<KeyValuePair
label="Maint Health"
value={`$${toUiDecimalsForQuote(
mangoAccount.getHealth(group, HealthType.maint),
).toFixed(4)}`}
/>
{/* <KeyValuePair
label="Perp Settle Health"
value={`$${toUiDecimalsForQuote(
mangoAccount.getPerpSettleHealth(group)
).toFixed(4)}`}
/> */}
<KeyValuePair
label="Net Deposits"
value={`$${toUiDecimalsForQuote(mangoAccount.netDeposits).toFixed(
4,
)}`}
/>
<KeyValuePair
label="Perp Spot Transfers"
value={mangoAccount.perpSpotTransfers.toNumber()}
/>
<KeyValuePair
label="Health Region Begin Init Health"
value={mangoAccount.healthRegionBeginInitHealth.toNumber()}
/>
<KeyValuePair
label="Perp OO Count"
value={mangoAccount.perpOpenOrders.length}
/>
<KeyValuePair
label="Perp Active OO Count"
value={mangoAccount.perpOrdersActive().length}
/>
<KeyValuePair
label="Perp Position Count"
value={mangoAccount.perps.length}
/>
<KeyValuePair
label="Active Perp Position Count"
value={mangoAccount.perpActive().length}
/>
<KeyValuePair
label="Token Position Count"
value={mangoAccount.tokens.length}
/>
<KeyValuePair
label="Active Token Position Count"
value={mangoAccount.tokensActive().length}
/>
<KeyValuePair
label="Serum OO Count"
value={mangoAccount.serum3.length}
/>
<KeyValuePair
label="Active Serum OO Count"
value={mangoAccount.serum3Active().length}
/>
<KeyValuePair
label="Net Deposits"
value={`$${toUiDecimalsForQuote(
mangoAccount.netDeposits,
).toFixed(4)}`}
/>
<KeyValuePair
label="Perp Spot Transfers"
value={mangoAccount.perpSpotTransfers.toNumber()}
/>
<KeyValuePair
label="Health Region Begin Init Health"
value={mangoAccount.healthRegionBeginInitHealth.toNumber()}
/>
<KeyValuePair
label="Perp OO Count"
value={mangoAccount.perpOpenOrders.length}
/>
<KeyValuePair
label="Perp Active OO Count"
value={mangoAccount.perpOrdersActive().length}
/>
<KeyValuePair
label="Perp Position Count"
value={mangoAccount.perps.length}
/>
<KeyValuePair
label="Active Perp Position Count"
value={mangoAccount.perpActive().length}
/>
<KeyValuePair
label="Token Position Count"
value={mangoAccount.tokens.length}
/>
<KeyValuePair
label="Active Token Position Count"
value={mangoAccount.tokensActive().length}
/>
<KeyValuePair
label="Serum OO Count"
value={mangoAccount.serum3.length}
/>
<KeyValuePair
label="Active Serum OO Count"
value={mangoAccount.serum3Active().length}
/>
<h3 className="mt-4">Token Active Positions</h3>
{mangoAccount.tokensActive().map((token) => {
const bank = group.getFirstBankByTokenIndex(token.tokenIndex)
return (
<div key={token.tokenIndex} className="mt-6">
<KeyValuePair label="Token's Bank Name" value={bank.name} />
<KeyValuePair
label="Deposits Native"
value={token.deposits(bank).toString()}
/>
<KeyValuePair
label="Borrow Native"
value={token.borrows(bank).toString()}
/>
<KeyValuePair
label="Balance UI"
value={token.balanceUi(bank)}
/>
<KeyValuePair
label="Value at oracle price"
value={`$${token.balanceUi(bank) * bank.uiPrice}`}
/>
<KeyValuePair
label="In Use Count"
value={`${token.inUseCount}`}
/>
</div>
)
})}
<h3 className="mt-4">Serum3 Active Positions</h3>
{mangoAccount.serum3Active().map((serum) => {
const market = group.getSerum3MarketByMarketIndex(serum.marketIndex)
const extMarket = group.getSerum3ExternalMarket(
market.serumMarketExternal,
)
return (
<div key={serum.marketIndex} className="mt-6">
<KeyValuePair
label="Serum Market"
value={<ExplorerLink address={market.publicKey.toString()} />}
/>
<KeyValuePair
label="Serum External Market"
value={
<ExplorerLink address={extMarket.publicKey.toString()} />
}
/>
<KeyValuePair label="Name" value={market.name} />
<KeyValuePair label="Market Index" value={serum.marketIndex} />
<KeyValuePair
label="Open Orders"
value={serum.openOrders.toBase58()}
/>
</div>
)
})}
<h3 className="mt-4">Perp Active Positions</h3>
{mangoAccount.perpActive().map((perp) => {
const market = group.getPerpMarketByMarketIndex(perp.marketIndex)
return (
<div key={perp.marketIndex} className="mt-6">
<KeyValuePair
label="Market"
value={<ExplorerLink address={market.publicKey.toString()} />}
/>
<KeyValuePair label="Market Index" value={perp.marketIndex} />
<KeyValuePair label="Name" value={market.name} />
<KeyValuePair
label="Base Position Lots"
value={perp.basePositionLots.toNumber()}
/>
<KeyValuePair
label="Base Position Ui"
value={perp.getBasePositionUi(market)}
/>
<KeyValuePair
label="Quote Position"
value={`$${toUiDecimalsForQuote(
perp.quotePositionNative,
).toFixed(4)}`}
/>
<KeyValuePair
label="Equity"
value={`$${perp.getEquityUi(market).toFixed(6)}`}
/>
<KeyValuePair
label="Unsettled Funding"
value={`$${toUiDecimalsForQuote(
perp.getUnsettledFunding(market),
).toFixed(6)}`}
/>
<KeyValuePair
label="Avg Entry Price"
value={`$${perp.getAverageEntryPriceUi(market).toFixed(6)}`}
/>
<KeyValuePair
label="Break even price"
value={`$${perp.getBreakEvenPriceUi(market).toFixed(6)}`}
/>
<KeyValuePair
label="Max Settle"
value={`$${toUiDecimalsForQuote(
mangoAccount.perpMaxSettle(group, market.settleTokenIndex),
).toFixed(6)}`}
/>
<KeyValuePair
label="Quote Running"
value={`$${toUiDecimalsForQuote(
perp.quoteRunningNative,
).toFixed(6)}`}
/>
<KeyValuePair
label="Cumulative Funding"
value={`$${toUiDecimalsForQuote(
-perp.cumulativeLongFunding,
).toFixed(6)} long / $${toUiDecimalsForQuote(
perp.cumulativeShortFunding,
).toFixed(6)} short / $${toUiDecimalsForQuote(
-perp.cumulativeLongFunding + perp.cumulativeShortFunding,
).toFixed(6)} total`}
/>
<KeyValuePair
label="Taker Lots"
value={`${perp.takerQuoteLots.toNumber()} quote / ${perp.takerBaseLots.toNumber()} base`}
/>
<KeyValuePair
label="Open Orders Lots"
value={`${perp.bidsBaseLots.toNumber()} bids / ${perp.asksBaseLots.toNumber()} asks`}
/>
<KeyValuePair
label="Has open orders"
value={perp.hasOpenOrders().toString()}
/>
<KeyValuePair
label="Volume"
value={`$${toUiDecimalsForQuote(perp.makerVolume).toFixed(
6,
)} maker / $${toUiDecimalsForQuote(perp.takerVolume).toFixed(
6,
)} taker`}
/>
<KeyValuePair
label="Perp-Spot Transfers"
value={`$${toUiDecimalsForQuote(
perp.perpSpotTransfers,
).toFixed(6)}`}
/>
<KeyValuePair
label="Position Lifetime PnL"
value={`$${toUiDecimalsForQuote(
perp.realizedPnlForPositionNative,
).toFixed(6)} realized / $${toUiDecimalsForQuote(
perp.cumulativePnlOverPositionLifetimeUi(market),
).toFixed(6)} total`}
/>
</div>
)
})}
<h3 className="mt-4">Perp Open Orders</h3>
{openOrders
? Object.entries(openOrders).map(([marketAddress, openOrders]) => {
<h3 className="mt-4">Token Active Positions</h3>
{mangoAccount.tokensActive().map((token) => {
const bank = group.getFirstBankByTokenIndex(token.tokenIndex)
return (
<div key={marketAddress} className="mt-4">
<div key={token.tokenIndex} className="mt-6">
<KeyValuePair label="Token's Bank Name" value={bank.name} />
<KeyValuePair
label="Market Address"
value={<ExplorerLink address={marketAddress} />}
label="Deposits Native"
value={token.deposits(bank).toString()}
/>
<KeyValuePair
label="Borrow Native"
value={token.borrows(bank).toString()}
/>
<KeyValuePair
label="Balance UI"
value={token.balanceUi(bank)}
/>
<KeyValuePair
label="Value at oracle price"
value={`$${token.balanceUi(bank) * bank.uiPrice}`}
/>
<KeyValuePair
label="In Use Count"
value={`${token.inUseCount}`}
/>
{openOrders.map((openOrder) => {
return (
<div
key={`${openOrder.orderId}${openOrder.side}${openOrder.seqNum}`}
className="mt-4 rounded border border-th-bkg-3 px-2"
>
<KeyValuePair
label="Side"
value={
openOrder.side
? 'bid' in openOrder.side
? 'Bid'
: 'Ask'
: null
}
/>
<KeyValuePair label="Price" value={openOrder.price} />
<KeyValuePair label="Size" value={openOrder.size} />
</div>
)
})}
</div>
)
})
: null}
})}
<h3 className="mt-4">Serum3 Active Positions</h3>
{mangoAccount.serum3Active().map((serum) => {
const market = group.getSerum3MarketByMarketIndex(
serum.marketIndex,
)
const extMarket = group.getSerum3ExternalMarket(
market.serumMarketExternal,
)
return (
<div key={serum.marketIndex} className="mt-6">
<KeyValuePair
label="Serum Market"
value={
<ExplorerLink address={market.publicKey.toString()} />
}
/>
<KeyValuePair
label="Serum External Market"
value={
<ExplorerLink
address={extMarket.publicKey.toString()}
/>
}
/>
<KeyValuePair label="Name" value={market.name} />
<KeyValuePair
label="Market Index"
value={serum.marketIndex}
/>
<KeyValuePair
label="Open Orders"
value={serum.openOrders.toBase58()}
/>
</div>
)
})}
<h3 className="mt-4">Perp Active Positions</h3>
{mangoAccount.perpActive().map((perp) => {
const market = group.getPerpMarketByMarketIndex(
perp.marketIndex,
)
return (
<div key={perp.marketIndex} className="mt-6">
<KeyValuePair
label="Market"
value={
<ExplorerLink address={market.publicKey.toString()} />
}
/>
<KeyValuePair
label="Market Index"
value={perp.marketIndex}
/>
<KeyValuePair label="Name" value={market.name} />
<KeyValuePair
label="Base Position Lots"
value={perp.basePositionLots.toNumber()}
/>
<KeyValuePair
label="Base Position Ui"
value={perp.getBasePositionUi(market)}
/>
<KeyValuePair
label="Quote Position"
value={`$${toUiDecimalsForQuote(
perp.quotePositionNative,
).toFixed(4)}`}
/>
<KeyValuePair
label="Equity"
value={`$${perp.getEquityUi(market).toFixed(6)}`}
/>
<KeyValuePair
label="Unsettled Funding"
value={`$${toUiDecimalsForQuote(
perp.getUnsettledFunding(market),
).toFixed(6)}`}
/>
<KeyValuePair
label="Avg Entry Price"
value={`$${perp
.getAverageEntryPriceUi(market)
.toFixed(6)}`}
/>
<KeyValuePair
label="Break even price"
value={`$${perp.getBreakEvenPriceUi(market).toFixed(6)}`}
/>
<KeyValuePair
label="Max Settle"
value={`$${toUiDecimalsForQuote(
mangoAccount.perpMaxSettle(
group,
market.settleTokenIndex,
),
).toFixed(6)}`}
/>
<KeyValuePair
label="Quote Running"
value={`$${toUiDecimalsForQuote(
perp.quoteRunningNative,
).toFixed(6)}`}
/>
<KeyValuePair
label="Cumulative Funding"
value={`$${toUiDecimalsForQuote(
-perp.cumulativeLongFunding,
).toFixed(6)} long / $${toUiDecimalsForQuote(
perp.cumulativeShortFunding,
).toFixed(6)} short / $${toUiDecimalsForQuote(
-perp.cumulativeLongFunding +
perp.cumulativeShortFunding,
).toFixed(6)} total`}
/>
<KeyValuePair
label="Taker Lots"
value={`${perp.takerQuoteLots.toNumber()} quote / ${perp.takerBaseLots.toNumber()} base`}
/>
<KeyValuePair
label="Open Orders Lots"
value={`${perp.bidsBaseLots.toNumber()} bids / ${perp.asksBaseLots.toNumber()} asks`}
/>
<KeyValuePair
label="Has open orders"
value={perp.hasOpenOrders().toString()}
/>
<KeyValuePair
label="Volume"
value={`$${toUiDecimalsForQuote(perp.makerVolume).toFixed(
6,
)} maker / $${toUiDecimalsForQuote(
perp.takerVolume,
).toFixed(6)} taker`}
/>
<KeyValuePair
label="Perp-Spot Transfers"
value={`$${toUiDecimalsForQuote(
perp.perpSpotTransfers,
).toFixed(6)}`}
/>
<KeyValuePair
label="Position Lifetime PnL"
value={`$${toUiDecimalsForQuote(
perp.realizedPnlForPositionNative,
).toFixed(6)} realized / $${toUiDecimalsForQuote(
perp.cumulativePnlOverPositionLifetimeUi(market),
).toFixed(6)} total`}
/>
</div>
)
})}
<h3 className="mt-4">Perp Open Orders</h3>
{openOrders
? Object.entries(openOrders).map(
([marketAddress, openOrders]) => {
return (
<div key={marketAddress} className="mt-4">
<KeyValuePair
label="Market Address"
value={<ExplorerLink address={marketAddress} />}
/>
{openOrders.map((openOrder) => {
return (
<div
key={`${openOrder.orderId}${openOrder.side}${openOrder.seqNum}`}
className="mt-4 rounded border border-th-bkg-3 px-2"
>
<KeyValuePair
label="Side"
value={
openOrder.side
? 'bid' in openOrder.side
? 'Bid'
: 'Ask'
: null
}
/>
<KeyValuePair
label="Price"
value={openOrder.price}
/>
<KeyValuePair
label="Size"
value={openOrder.size}
/>
</div>
)
})}
</div>
)
},
)
: null}
</div>
) : (
<div className="m-4 flex items-center">Loading account data...</div>
)}
</div>
) : (
<div className="m-4 flex items-center">Loading account data...</div>
)}
</div>
</div>
</>
)
}

View File

@ -81,16 +81,18 @@ const RiskDashboard: NextPage = () => {
)
return (
<div className="col-span-12 lg:col-span-8 lg:col-start-3">
<div>
<DashboardNavbar />
{data?.timestamp ? <h6> As of: {data.timestamp} UTC </h6> : null}
{data?.timestamp ? (
<h6 className="mx-4 mt-4 md:mx-6"> As of: {data.timestamp} UTC </h6>
) : null}
{group && data && data.payload ? (
<div className="mt-4">
{Object.entries(data.payload).map(
([tableType, table]: [string, TableData]) => {
if (!table?.data?.length) return null
return (
<div className="mt-12" key={tableType}>
<div className="px-4 md:px-6" key={tableType}>
<div className="mb-4">
<p className="text-th-fgd-4">{table.title}</p>
</div>