mango-v4-ui/pages/dashboard/index.tsx

659 lines
29 KiB
TypeScript
Raw Normal View History

import {
Bank,
toUiDecimals,
I80F48,
toUiDecimalsForQuote,
} from '@blockworks-foundation/mango-v4'
2022-12-08 14:13:06 -08:00
import ExplorerLink from '@components/shared/ExplorerLink'
import { coder } from '@project-serum/anchor/dist/cjs/spl/token'
import mangoStore from '@store/mangoStore'
import useMangoGroup from 'hooks/useMangoGroup'
import type { NextPage } from 'next'
2022-12-08 19:07:28 -08:00
import { ReactNode, useCallback, useEffect, useState } from 'react'
2022-12-08 14:13:06 -08:00
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
2022-12-08 19:07:28 -08:00
import useJupiterMints from 'hooks/useJupiterMints'
import Image from 'next/image'
2022-12-11 17:11:31 -08:00
import {
ChevronDownIcon,
QuestionMarkCircleIcon,
} from '@heroicons/react/20/solid'
import { Disclosure } from '@headlessui/react'
import MarketLogos from '@components/trade/MarketLogos'
import Button from '@components/shared/Button'
2022-12-08 14:13:06 -08:00
export async function getStaticProps({ locale }: { locale: string }) {
return {
props: {
2022-12-19 17:47:15 -08:00
...(await serverSideTranslations(locale, [
'common',
'onboarding',
'profile',
2023-01-10 18:46:18 -08:00
'search',
2022-12-19 17:47:15 -08:00
'settings',
'token',
'trade',
])),
2022-12-08 14:13:06 -08:00
},
}
}
const Dashboard: NextPage = () => {
const { group } = useMangoGroup()
2022-12-08 19:07:28 -08:00
const { mangoTokens } = useJupiterMints()
2022-12-08 14:13:06 -08:00
// const client = mangoStore(s => s.client)
2022-12-11 17:11:31 -08:00
// const handleClickScroll = (id: string) => {
// const element = document.getElementById(id)
// if (element) {
// element.scrollIntoView({ behavior: 'smooth' })
// }
// }
2022-12-08 14:13:06 -08:00
2022-12-08 19:07:28 -08:00
return (
<div className="grid grid-cols-12">
2023-01-24 10:08:35 -08:00
<div className="col-span-12 lg:col-span-8 lg:col-start-3">
2022-12-08 19:07:28 -08:00
<div className="p-8 pb-20 md:pb-16 lg:p-10">
<h1>Dashboard</h1>
{group ? (
<div className="mt-4">
<h2 className="mb-2">Group</h2>
<ExplorerLink
address={group?.publicKey.toString()}
anchorData
></ExplorerLink>
<div className="mt-4 flex space-x-4">
<Button
secondary
size="small"
onClick={() => {
const panels = [
...document.querySelectorAll(
'[aria-expanded=false][aria-label=panel]'
),
]
panels.map((panel) => (panel as HTMLElement).click())
}}
>
Expand All
</Button>
<Button
secondary
size="small"
onClick={() => {
const panels = [
...document.querySelectorAll(
'[aria-expanded=true][aria-label=panel]'
),
]
panels.map((panel) => (panel as HTMLElement).click())
}}
>
Collpase All
</Button>
</div>
2022-12-11 17:11:31 -08:00
<h3 className="mt-6 mb-3 text-base text-th-fgd-3">Banks</h3>
<div className="border-b border-th-bkg-3">
2023-01-16 14:43:20 -08:00
{Array.from(group.banksMapByMint)
.sort((a, b) => a[0].localeCompare(b[0]))
.map(([mintAddress, banks]) =>
banks.map((bank) => {
const mintInfo = group.mintInfosMapByMint.get(
bank.mint.toString()
)
2023-01-16 14:43:20 -08:00
const logoUri = mangoTokens.length
? mangoTokens.find((t) => t.address === mintAddress)
?.logoURI
: ''
return (
<Disclosure key={bank.publicKey.toString()}>
{({ open }) => (
<>
<Disclosure.Button
aria-label="panel"
2023-01-24 10:08:35 -08:00
className={`default-transition flex w-full items-center justify-between border-t border-th-bkg-3 p-4 md:hover:bg-th-bkg-4 ${
open ? 'bg-th-bkg-4' : ''
2023-01-16 14:43:20 -08:00
}`}
>
<div className="flex items-center">
{logoUri ? (
<Image
alt=""
width="20"
height="20"
src={logoUri}
/>
) : (
<QuestionMarkCircleIcon className="h-6 w-6 text-th-fgd-3" />
)}
<p className="ml-2 text-th-fgd-2">
{bank.name} Bank
</p>
</div>
<ChevronDownIcon
className={`${
open ? 'rotate-180' : 'rotate-360'
} h-5 w-5 text-th-fgd-3`}
/>
</Disclosure.Button>
<Disclosure.Panel>
<KeyValuePair
label="Mint"
value={<ExplorerLink address={mintAddress} />}
/>
<KeyValuePair
label="Bank"
value={
<ExplorerLink
address={bank.publicKey.toString()}
anchorData
/>
}
/>
<KeyValuePair
label="Vault"
value={
<ExplorerLink
address={bank.vault.toString()}
anchorData
/>
}
/>
<KeyValuePair
label="Oracle"
value={
<ExplorerLink
address={bank.oracle.toString()}
/>
}
/>
<KeyValuePair
label="Token Index"
value={bank.tokenIndex}
/>
<KeyValuePair
label="Oracle Price"
value={`$${bank.uiPrice}`}
/>
<KeyValuePair
label="Stable Price"
value={`$${group.toUiPrice(
I80F48.fromNumber(
bank.stablePriceModel.stablePrice
),
bank.mintDecimals
)}`}
/>
<VaultData bank={bank} />
<KeyValuePair
label="Loan Fee Rate"
value={`${(
10000 * bank.loanFeeRate.toNumber()
).toFixed(2)} bps`}
/>
<KeyValuePair
label="Loan origination fee rate"
value={`${(
10000 *
bank.loanOriginationFeeRate.toNumber()
).toFixed(2)} bps`}
/>
<KeyValuePair
label="Collected fees native"
value={bank.collectedFeesNative.toNumber()}
/>
<KeyValuePair
label="Dust"
value={bank.dust.toNumber()}
/>
<KeyValuePair
label="Deposits"
value={toUiDecimals(
bank.indexedDeposits
.mul(bank.depositIndex)
.toNumber(),
bank.mintDecimals
)}
/>
<KeyValuePair
label="Borrows"
value={toUiDecimals(
bank.indexedBorrows
.mul(bank.borrowIndex)
.toNumber(),
bank.mintDecimals
)}
/>
<KeyValuePair
label="Avg Utilization"
value={`${
bank.avgUtilization.toNumber() * 100
}%`}
/>
<KeyValuePair
label="Maint Asset/Liab Weight"
value={`${bank.maintAssetWeight.toFixed(2)}/
2022-12-08 19:07:28 -08:00
${bank.maintLiabWeight.toFixed(2)}`}
2023-01-16 14:43:20 -08:00
/>
<KeyValuePair
label="Init Asset/Liab Weight"
value={`${bank.initAssetWeight.toFixed(2)}/
2022-12-08 19:07:28 -08:00
${bank.initLiabWeight.toFixed(2)}`}
2023-01-16 14:43:20 -08:00
/>
<KeyValuePair
label="Deposit weight scale start quote"
value={`${toUiDecimalsForQuote(
bank.depositWeightScaleStartQuote
)}$`}
2023-01-16 14:43:20 -08:00
/>
<KeyValuePair
label="Borrow weight scale start quote"
value={`${toUiDecimalsForQuote(
bank.borrowWeightScaleStartQuote
)}$`}
2023-01-16 14:43:20 -08:00
/>
<KeyValuePair
label="Rate params"
value={
<span className="text-right">
{`${(100 * bank.rate0.toNumber()).toFixed(
2
)}% @ ${(
100 * bank.util0.toNumber()
).toFixed()}% util, `}
{`${(100 * bank.rate1.toNumber()).toFixed(
2
)}% @ ${(
100 * bank.util1.toNumber()
).toFixed()}% util, `}
{`${(
100 * bank.maxRate.toNumber()
).toFixed(2)}% @ 100% util`}
</span>
}
/>
<KeyValuePair
label="Deposit rate"
value={`${bank.getDepositRateUi()}%`}
/>
<KeyValuePair
label="Borrow rate"
value={`${bank.getBorrowRateUi()}%`}
/>
<KeyValuePair
label="Last index update"
value={new Date(
1000 * bank.indexLastUpdated.toNumber()
).toUTCString()}
/>
<KeyValuePair
label="Last rates updated"
value={new Date(
1000 * bank.bankRateLastUpdated.toNumber()
).toUTCString()}
/>
<KeyValuePair
label="Last stable price updated"
value={new Date(
1000 *
bank.stablePriceModel.lastUpdateTimestamp.toNumber()
).toUTCString()}
/>
<KeyValuePair
label="Stable Price: delay interval"
value={`${bank.stablePriceModel.delayIntervalSeconds}s`}
/>
<KeyValuePair
label="Stable Price: growth limits"
value={`${(
100 * bank.stablePriceModel.delayGrowthLimit
).toFixed(2)}% delay / ${(
100 *
bank.stablePriceModel.stableGrowthLimit
).toFixed(2)}% stable`}
/>
<KeyValuePair
label="Oracle: Conf Filter"
value={`${(
100 *
bank.oracleConfig.confFilter.toNumber()
).toFixed(2)}%`}
/>
<KeyValuePair
label="Oracle: Max Staleness"
value={`${bank.oracleConfig.maxStalenessSlots} slots`}
/>
<KeyValuePair
label="Group Insurance Fund"
value={`${mintInfo!.groupInsuranceFund}`}
/>
2023-01-16 14:43:20 -08:00
<KeyValuePair
label="Min vault to deposits ratio"
value={`${
bank.minVaultToDepositsRatio * 100
}%`}
/>
<KeyValuePair
label="Net borrows in window / Net borrow limit per window quote"
value={`${toUiDecimals(
bank.netBorrowsInWindow.toNumber(),
6
)}$ / ${toUiDecimals(
bank.netBorrowLimitPerWindowQuote.toNumber(),
6
)}$`}
2023-01-16 14:43:20 -08:00
/>
<KeyValuePair
label="Liquidation fee"
value={`${
bank.liquidationFee.toNumber() * 100
}%`}
/>
2023-01-16 14:43:20 -08:00
</Disclosure.Panel>
</>
)}
</Disclosure>
)
})
)}
2022-12-11 17:11:31 -08:00
</div>
2022-12-11 02:29:03 -08:00
2022-12-11 17:11:31 -08:00
<h3 className="mt-6 mb-3 text-base text-th-fgd-3">
Perp Markets
</h3>
<div className="border-b border-th-bkg-3">
{Array.from(group.perpMarketsMapByOracle).map(
([oracle, perpMarket]) => {
return (
<Disclosure key={oracle.toString()}>
{({ open }) => (
<>
<Disclosure.Button
aria-label="panel"
2022-12-11 17:11:31 -08:00
className={`default-transition flex w-full items-center justify-between border-t border-th-bkg-3 p-4 md:hover:bg-th-bkg-2 ${
open ? 'bg-th-bkg-2' : ''
}`}
>
<div className="flex items-center">
<MarketLogos market={perpMarket} />
<p className="text-th-fgd-2">
{perpMarket.name}
</p>
</div>
<ChevronDownIcon
className={`${
open ? 'rotate-180' : 'rotate-360'
} h-5 w-5 text-th-fgd-3`}
/>
</Disclosure.Button>
<Disclosure.Panel>
<KeyValuePair
label="Perp Market"
value={
<ExplorerLink
address={perpMarket.publicKey.toString()}
anchorData
/>
}
/>
<KeyValuePair
label="Bids"
value={
<ExplorerLink
address={perpMarket.bids.toString()}
anchorData
/>
}
/>
<KeyValuePair
label="Asks"
value={
<ExplorerLink
address={perpMarket.asks.toString()}
anchorData
/>
}
/>
<KeyValuePair
label="Event Queue"
value={
<ExplorerLink
address={perpMarket.eventQueue.toString()}
anchorData
/>
}
/>
<KeyValuePair
label="Oracle"
value={
<ExplorerLink
address={perpMarket.oracle.toString()}
/>
}
/>
<KeyValuePair
label="Perp Market Index"
value={perpMarket.perpMarketIndex}
/>
<KeyValuePair
label="Reduce Only"
value={perpMarket.reduceOnly ? 'True' : 'False'}
/>
2022-12-11 17:11:31 -08:00
<KeyValuePair
label="Oracle Price"
value={`$${perpMarket.uiPrice}`}
/>
<KeyValuePair
label="Stable Price"
value={`$${group.toUiPrice(
I80F48.fromNumber(
perpMarket.stablePriceModel.stablePrice
),
perpMarket.baseDecimals
)}`}
/>
<KeyValuePair
label="Open Interest"
value={`${perpMarket.openInterest} lots`}
/>
<KeyValuePair
label="Lot Sizes"
value={`${perpMarket.baseLotSize} base /
2022-12-11 08:40:34 -08:00
${perpMarket.quoteLotSize} quote`}
2022-12-11 17:11:31 -08:00
/>
<KeyValuePair
label="Maint Asset/Liab Weight"
value={`${perpMarket.maintBaseAssetWeight.toFixed(
2022-12-11 17:11:31 -08:00
4
)}/
${perpMarket.maintBaseLiabWeight.toFixed(4)}`}
2022-12-11 17:11:31 -08:00
/>
<KeyValuePair
label="Init Asset/Liab Weight"
value={`${perpMarket.initBaseAssetWeight.toFixed(
2022-12-11 17:11:31 -08:00
4
)}/
${perpMarket.initBaseLiabWeight.toFixed(4)}`}
/>
<KeyValuePair
label="Base liquidation fee"
value={`${
10000 *
perpMarket.baseLiquidationFee.toNumber()
} bps`}
/>
2022-12-11 17:11:31 -08:00
<KeyValuePair
label="Trading Fees"
value={`${(
10000 * perpMarket.makerFee.toNumber()
).toFixed(2)} bps maker / ${(
10000 * perpMarket.takerFee.toNumber()
).toFixed(2)} bps taker`}
/>
<KeyValuePair
label="Funding Limits"
value={`${(
100 * perpMarket.minFunding.toNumber()
).toFixed(2)}% to ${(
100 * perpMarket.maxFunding.toNumber()
).toFixed(2)}%`}
/>
<KeyValuePair
label="Fees Accrued"
value={`$${toUiDecimals(
perpMarket.feesAccrued,
6
)}`}
/>
<KeyValuePair
label="Fees Settled"
value={`$${toUiDecimals(
perpMarket.feesSettled,
6
)}`}
/>
<KeyValuePair
label="Last stable price updated"
value={new Date(
1000 *
perpMarket.stablePriceModel.lastUpdateTimestamp.toNumber()
).toUTCString()}
/>
<KeyValuePair
label="Stable Price: delay interval"
value={`${perpMarket.stablePriceModel.delayIntervalSeconds}s`}
/>
<KeyValuePair
label="Stable Price: growth limits"
value={`${(
100 *
perpMarket.stablePriceModel.delayGrowthLimit
).toFixed(2)}% delay / ${(
100 *
perpMarket.stablePriceModel.stableGrowthLimit
).toFixed(2)}% stable`}
/>
2022-12-11 17:11:31 -08:00
<KeyValuePair
label="Oracle: Conf Filter"
value={`${(
100 *
perpMarket.oracleConfig.confFilter.toNumber()
).toFixed(2)}%`}
/>
<KeyValuePair
label="Oracle: Max Staleness"
value={`${perpMarket.oracleConfig.maxStalenessSlots} slots`}
/>
<KeyValuePair
label="Group Insurance Fund"
value={`${perpMarket.groupInsuranceFund}`}
/>
<KeyValuePair
label="Fee penalty"
value={`${toUiDecimals(
perpMarket.feePenalty,
6
)}$`}
/>
<KeyValuePair
label="Settle fee flat"
value={`${toUiDecimals(
perpMarket.settleFeeFlat,
6
)}$`}
/>
<KeyValuePair
label="Settle fee amount threshold"
value={`${toUiDecimals(
perpMarket.settleFeeAmountThreshold,
6
)}$`}
/>
<KeyValuePair
label="Settle fee fraction low health"
value={`${perpMarket.settleFeeFractionLowHealth.toFixed(
4
)}`}
/>
<KeyValuePair
label="Settle pnl limit factor"
value={`${perpMarket.settlePnlLimitFactor}`}
/>
<KeyValuePair
label="Settle pnl limit window size ts"
value={`${perpMarket.settlePnlLimitWindowSizeTs.toNumber()}`}
/>
<KeyValuePair
label="Maint overall asset weight"
value={`${perpMarket.maintOverallAssetWeight.toNumber()}`}
/>
<KeyValuePair
label="Init overall asset weight"
value={`${perpMarket.initOverallAssetWeight.toNumber()}`}
/>
{/* this property will land in client soon */}
{/* <KeyValuePair
label="Positive pnl liquidation fee"
value={`${perpMarket.positivePnlLiquidationFee}`}
/> */}
2022-12-11 17:11:31 -08:00
</Disclosure.Panel>
</>
)}
</Disclosure>
)
}
)}
</div>
2022-12-08 19:07:28 -08:00
</div>
) : (
'Loading'
)}
2022-12-08 14:13:06 -08:00
</div>
2022-12-08 19:07:28 -08:00
</div>
</div>
)
}
const KeyValuePair = ({
label,
value,
}: {
label: string
value: number | ReactNode | string
}) => {
return (
2023-01-24 10:08:35 -08:00
<div className="flex justify-between border-t border-th-bkg-2 px-6 py-3">
2022-12-08 22:49:01 -08:00
<span className="mr-4 whitespace-nowrap text-th-fgd-3">{label}</span>
2023-01-24 10:08:35 -08:00
<span className="font-mono text-th-fgd-2">{value}</span>
2022-12-08 14:13:06 -08:00
</div>
)
}
const VaultData = ({ bank }: { bank: Bank }) => {
const [vault, setVault] = useState<any>()
const client = mangoStore((s) => s.client)
const getVaultData = useCallback(async () => {
const res = await client.program.provider.connection.getAccountInfo(
bank.vault
)
const v = res?.data ? coder().accounts.decode('token', res.data) : undefined
setVault(v)
}, [bank.vault])
useEffect(() => {
getVaultData()
}, [getVaultData])
return (
2022-12-08 19:07:28 -08:00
<KeyValuePair
label="Vault balance"
value={
vault ? toUiDecimals(vault.amount.toNumber(), bank.mintDecimals) : '...'
}
/>
2022-12-08 14:13:06 -08:00
)
}
export default Dashboard