warnings and layout fixes
This commit is contained in:
parent
69a32541a6
commit
82925628c7
|
@ -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)" />
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue