Feature/dashboard improvements (#389)
* suggested and current tier * switchboard icon
This commit is contained in:
parent
a872420b19
commit
39367f1d22
|
@ -0,0 +1,38 @@
|
|||
const SwitchboardIcon = ({ className }: { className?: string }) => (
|
||||
<svg
|
||||
className={`${className}`}
|
||||
width="50"
|
||||
height="50"
|
||||
viewBox="0 0 77 59"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g id="Logo-/-Branding" stroke="none" fill="none">
|
||||
<g
|
||||
id="Artboard-Copy-13"
|
||||
transform="translate(-190.000000, -216.000000)"
|
||||
fill="#4c6fff"
|
||||
>
|
||||
<g id="Group-2" transform="translate(190.073984, 216.936658)">
|
||||
<g id="Group-2-Copy" transform="translate(7.793510, 0.000000)">
|
||||
<path
|
||||
d="M0,20.5618692 C0,8.37745584 8.46049721,0.23471226 21.504123,0 L68.949953,0 C66.1199986,6.2431525 63.8418731,9.40858447 62.1155763,9.49629592 L21.0826801,9.49629592 C13.9789978,9.51541386 9.70259597,13.6455584 9.70259597,20.5618692 C9.70259597,27.4032667 13.9656204,31.8262383 20.8431235,31.8537325 L39.0136632,31.8262382 C41.6527581,31.8537324 43.9144823,34.1278864 43.9144823,36.8658935 C43.9144823,39.6039006 41.8553038,41.1874861 39.2658587,41.3190533 L21.3712044,41.3397319 C8.62248533,41.3397319 0.195863032,32.9187591 0.00336072172,20.9793638 L0,20.5618692 Z"
|
||||
id="Combined-Shape-Copy-6"
|
||||
></path>
|
||||
</g>
|
||||
<g
|
||||
id="Group-2-Copy"
|
||||
transform="translate(34.474977, 36.656819) scale(-1, -1) translate(-34.474977, -36.656819) translate(0.000000, 15.986953)"
|
||||
>
|
||||
<path
|
||||
d="M0,20.5618692 C0,8.37745584 8.46049721,0.23471226 21.504123,0 L68.949953,0 C66.1199986,6.2431525 63.8418731,9.40858447 62.1155763,9.49629592 L21.0826801,9.49629592 C13.9789978,9.51541386 9.70259597,13.6455584 9.70259597,20.5618692 C9.70259597,27.4032667 13.9656204,31.8262383 20.8431235,31.8537325 L39.0136632,31.8262382 C41.6527581,31.8537324 43.9144823,34.1278864 43.9144823,36.8658935 C43.9144823,39.6039006 41.8553038,41.1874861 39.2658587,41.3190533 L21.3712044,41.3397319 C8.62248533,41.3397319 0.195863032,32.9187591 0.00336072172,20.9793638 L0,20.5618692 Z"
|
||||
id="Combined-Shape-Copy-5"
|
||||
></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default SwitchboardIcon
|
|
@ -1,4 +1,4 @@
|
|||
import { ReactNode, useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { ReactNode, useCallback, useEffect, useState } from 'react'
|
||||
import { ModalProps } from '../../types/modal'
|
||||
import Modal from '../shared/Modal'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
|
@ -6,13 +6,13 @@ import { useWallet } from '@solana/wallet-adapter-react'
|
|||
import GovernanceStore from '@store/governanceStore'
|
||||
import {
|
||||
formatSuggestedValues,
|
||||
getApiTokenName,
|
||||
getFormattedBankValues,
|
||||
} from 'utils/governance/listingTools'
|
||||
import {
|
||||
Bank,
|
||||
Group,
|
||||
OracleProvider,
|
||||
PriceImpact,
|
||||
toUiDecimals,
|
||||
} from '@blockworks-foundation/mango-v4'
|
||||
import { AccountMeta, Transaction } from '@solana/web3.js'
|
||||
|
@ -34,10 +34,8 @@ import {
|
|||
LISTING_PRESETS,
|
||||
LISTING_PRESETS_KEY,
|
||||
MidPriceImpact,
|
||||
getMidPriceImpacts,
|
||||
getPresetWithAdjustedDepositLimit,
|
||||
getPresetWithAdjustedNetBorrows,
|
||||
getProposedKey,
|
||||
getPythPresets,
|
||||
getSwitchBoardPresets,
|
||||
} from '@blockworks-foundation/mango-v4-settings/lib/helpers/listingTools'
|
||||
|
@ -52,11 +50,15 @@ const DashboardSuggestedValues = ({
|
|||
onClose,
|
||||
bank,
|
||||
group,
|
||||
priceImpacts,
|
||||
suggestedTierKey,
|
||||
currentTier,
|
||||
midPriceImp,
|
||||
}: ModalProps & {
|
||||
bank: Bank
|
||||
group: Group
|
||||
priceImpacts: PriceImpact[]
|
||||
suggestedTierKey: LISTING_PRESETS_KEY
|
||||
currentTier: LISTING_PRESET | undefined
|
||||
midPriceImp: MidPriceImpact[]
|
||||
}) => {
|
||||
const client = mangoStore((s) => s.client)
|
||||
//do not deconstruct wallet is used for anchor to sign
|
||||
|
@ -74,63 +76,13 @@ const DashboardSuggestedValues = ({
|
|||
: getSwitchBoardPresets(LISTING_PRESETS)
|
||||
|
||||
const [proposedTier, setProposedTier] =
|
||||
useState<LISTING_PRESETS_KEY>('liab_1')
|
||||
const [suggestedTier, setSuggestedTier] =
|
||||
useState<LISTING_PRESETS_KEY>('liab_1')
|
||||
useState<LISTING_PRESETS_KEY>(suggestedTierKey)
|
||||
const [proposing, setProposing] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
setForcePythOracle(bank?.oracleProvider === OracleProvider.Pyth)
|
||||
}, [bank.oracleProvider])
|
||||
|
||||
const getApiTokenName = (bankName: string) => {
|
||||
if (bankName === 'ETH (Portal)') {
|
||||
return 'ETH'
|
||||
}
|
||||
return bankName
|
||||
}
|
||||
const priceImpactsFiltered = useMemo(
|
||||
() =>
|
||||
getMidPriceImpacts(priceImpacts.length ? priceImpacts : []).filter(
|
||||
(x) => x.symbol === getApiTokenName(bank.name),
|
||||
),
|
||||
[priceImpacts, bank.name],
|
||||
)
|
||||
|
||||
const currentTier = useMemo(() => {
|
||||
return Object.values(LISTING_PRESETS).find((x) =>
|
||||
x.initLiabWeight.toFixed(1) === '1.8'
|
||||
? x.initLiabWeight.toFixed(1) ===
|
||||
bank?.initLiabWeight.toNumber().toFixed(1) &&
|
||||
x.reduceOnly === bank.reduceOnly
|
||||
: x.initLiabWeight.toFixed(1) ===
|
||||
bank?.initLiabWeight.toNumber().toFixed(1),
|
||||
)
|
||||
}, [bank.initLiabWeight])
|
||||
|
||||
const getSuggestedTierForListedTokens = useCallback(async () => {
|
||||
const filteredResp = priceImpactsFiltered
|
||||
.filter((x) => x.avg_price_impact_percent < 1)
|
||||
.reduce((acc: { [key: string]: MidPriceImpact }, val: MidPriceImpact) => {
|
||||
if (
|
||||
!acc[val.symbol] ||
|
||||
val.target_amount > acc[val.symbol].target_amount
|
||||
) {
|
||||
acc[val.symbol] = val
|
||||
}
|
||||
return acc
|
||||
}, {})
|
||||
const priceImpact = filteredResp[getApiTokenName(bank.name)]
|
||||
|
||||
const suggestedTier = getProposedKey(
|
||||
priceImpact?.target_amount,
|
||||
bank.oracleProvider === OracleProvider.Pyth,
|
||||
)
|
||||
|
||||
setProposedTier(suggestedTier)
|
||||
setSuggestedTier(suggestedTier)
|
||||
}, [bank.name, bank.oracleProvider, priceImpactsFiltered.toString()])
|
||||
|
||||
const proposeNewSuggestedValues = useCallback(
|
||||
async (
|
||||
bank: Bank,
|
||||
|
@ -148,6 +100,7 @@ const DashboardSuggestedValues = ({
|
|||
bank.uiPrice,
|
||||
bank.mintDecimals,
|
||||
)
|
||||
console.log(preset)
|
||||
|
||||
const fieldsToChange = invalidFieldsKeys.reduce(
|
||||
(obj, key) => ({ ...obj, [key]: preset[key as keyof typeof preset] }),
|
||||
|
@ -314,6 +267,7 @@ const DashboardSuggestedValues = ({
|
|||
connection,
|
||||
fee,
|
||||
group,
|
||||
oracle,
|
||||
proposals,
|
||||
voter.tokenOwnerRecord,
|
||||
vsrClient,
|
||||
|
@ -321,10 +275,6 @@ const DashboardSuggestedValues = ({
|
|||
],
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
getSuggestedTierForListedTokens()
|
||||
}, [getSuggestedTierForListedTokens])
|
||||
|
||||
const mintInfo = group.mintInfosMapByMint.get(bank.mint.toString())
|
||||
|
||||
const formattedBankValues = getFormattedBankValues(group, bank)
|
||||
|
@ -376,8 +326,8 @@ const DashboardSuggestedValues = ({
|
|||
>
|
||||
<h3 className="mb-6">
|
||||
<span>
|
||||
{bank.name} - Suggested tier: {PRESETS[suggestedTier].preset_name}{' '}
|
||||
Current tier: ~{currentTier?.preset_name}
|
||||
{bank.name} - Suggested tier: {PRESETS[suggestedTierKey].preset_name}{' '}
|
||||
Current tier: ~ {currentTier?.preset_name}
|
||||
</span>
|
||||
<div className="py-4">
|
||||
<p className="mb-2">
|
||||
|
@ -398,7 +348,7 @@ const DashboardSuggestedValues = ({
|
|||
<div className="flex w-full items-center justify-between">
|
||||
{PRESETS[name as LISTING_PRESETS_KEY].preset_name}{' '}
|
||||
{`{${PRESETS[name as LISTING_PRESETS_KEY].preset_key}}`}
|
||||
{name === suggestedTier ? '- suggested' : ''}
|
||||
{name === suggestedTierKey ? ' - suggested' : ''}
|
||||
</div>
|
||||
</Select.Option>
|
||||
))}
|
||||
|
@ -668,18 +618,20 @@ const DashboardSuggestedValues = ({
|
|||
/>
|
||||
<div>
|
||||
<h3 className="mb-4 pl-6">Price impacts</h3>
|
||||
{priceImpactsFiltered.map((x) => (
|
||||
<div className="flex pl-6" key={x.target_amount}>
|
||||
<p className="mr-4 w-[150px] space-x-4">
|
||||
<span>Amount:</span>
|
||||
<span>${x.target_amount}</span>
|
||||
</p>
|
||||
<p className="space-x-4">
|
||||
<span>Price impact:</span>{' '}
|
||||
<span>{x.avg_price_impact_percent.toFixed(3)}%</span>
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
{midPriceImp
|
||||
.filter((x) => x.symbol === getApiTokenName(bank.name))
|
||||
.map((x) => (
|
||||
<div className="flex pl-6" key={x.target_amount}>
|
||||
<p className="mr-4 w-[150px] space-x-4">
|
||||
<span>Amount:</span>
|
||||
<span>${x.target_amount}</span>
|
||||
</p>
|
||||
<p className="space-x-4">
|
||||
<span>Price impact:</span>{' '}
|
||||
<span>{x.avg_price_impact_percent.toFixed(3)}%</span>
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Disclosure.Panel>
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { Bank } from '@blockworks-foundation/mango-v4'
|
||||
import PythIcon from '@components/icons/PythIcon'
|
||||
import SwitchboardIcon from '@components/icons/SwitchboardIcon'
|
||||
import { ArrowTopRightOnSquareIcon } from '@heroicons/react/20/solid'
|
||||
import useOracleProvider from 'hooks/useOracleProvider'
|
||||
|
||||
|
@ -16,6 +17,9 @@ const OracleProvider = ({ bank }: { bank?: Bank }) => {
|
|||
{oracleProvider === 'Pyth' ? (
|
||||
<PythIcon className="mr-1.5 h-4 w-4" />
|
||||
) : null}
|
||||
{oracleProvider === 'Switchboard' ? (
|
||||
<SwitchboardIcon className="mr-1.5 h-4 w-4" />
|
||||
) : null}
|
||||
<span className="mr-1.5">{oracleProvider}</span>
|
||||
<ArrowTopRightOnSquareIcon className="h-4 w-4" />
|
||||
</a>
|
||||
|
|
|
@ -10,7 +10,7 @@ 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'
|
||||
import { ReactNode, useCallback, useEffect, useState } from 'react'
|
||||
import { ReactNode, useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
|
||||
import {
|
||||
ArrowTopRightOnSquareIcon,
|
||||
|
@ -23,8 +23,8 @@ import BN from 'bn.js'
|
|||
import { useRouter } from 'next/router'
|
||||
import Link from 'next/link'
|
||||
import {
|
||||
getApiTokenName,
|
||||
getFormattedBankValues,
|
||||
getPriceImpacts,
|
||||
} from 'utils/governance/listingTools'
|
||||
import GovernancePageWrapper from '@components/governance/GovernancePageWrapper'
|
||||
import TokenLogo from '@components/shared/TokenLogo'
|
||||
|
@ -37,6 +37,12 @@ import { PythHttpClient } from '@pythnetwork/client'
|
|||
import { MAINNET_PYTH_PROGRAM } from 'utils/governance/constants'
|
||||
import { PublicKey } from '@solana/web3.js'
|
||||
import { notify } from 'utils/notifications'
|
||||
import {
|
||||
LISTING_PRESETS,
|
||||
MidPriceImpact,
|
||||
getMidPriceImpacts,
|
||||
getProposedKey,
|
||||
} from '@blockworks-foundation/mango-v4-settings/lib/helpers/listingTools'
|
||||
|
||||
dayjs.extend(relativeTime)
|
||||
|
||||
|
@ -63,10 +69,51 @@ const Dashboard: NextPage = () => {
|
|||
const { group } = useMangoGroup()
|
||||
const connection = mangoStore((s) => s.connection)
|
||||
const { banks } = useBanks()
|
||||
const [isOpenSuggestionModal, setIsOpenSuggestionModal] = useState(false)
|
||||
const [priceImpacts, setPriceImapcts] = useState<PriceImpact[]>([])
|
||||
const [openedSuggestedModal, setOpenedSuggestedModal] = useState<
|
||||
string | null
|
||||
>(null)
|
||||
const priceImpacts: PriceImpact[] = group?.pis || []
|
||||
const [stickyIndex, setStickyIndex] = useState(-1)
|
||||
|
||||
const midPriceImp = useMemo(
|
||||
() => getMidPriceImpacts(priceImpacts.length ? priceImpacts : []),
|
||||
[priceImpacts],
|
||||
)
|
||||
|
||||
const getSuggestedAndCurrentTier = (bank: Bank) => {
|
||||
const currentTier = Object.values(LISTING_PRESETS).find((x) => {
|
||||
return x.initLiabWeight.toFixed(1) === '1.8'
|
||||
? x.initLiabWeight.toFixed(1) ===
|
||||
bank?.initLiabWeight.toNumber().toFixed(1) &&
|
||||
x.reduceOnly === bank.reduceOnly
|
||||
: x.initLiabWeight.toFixed(1) ===
|
||||
bank?.initLiabWeight.toNumber().toFixed(1)
|
||||
})
|
||||
|
||||
const filteredResp = midPriceImp
|
||||
.filter((x) => x.avg_price_impact_percent < 1)
|
||||
.reduce((acc: { [key: string]: MidPriceImpact }, val: MidPriceImpact) => {
|
||||
if (
|
||||
!acc[val.symbol] ||
|
||||
val.target_amount > acc[val.symbol].target_amount
|
||||
) {
|
||||
acc[val.symbol] = val
|
||||
}
|
||||
return acc
|
||||
}, {})
|
||||
const priceImpact = filteredResp[getApiTokenName(bank.name)]
|
||||
|
||||
const suggestedTierKey = getProposedKey(
|
||||
priceImpact?.target_amount,
|
||||
bank.oracleProvider === OracleProvider.Pyth,
|
||||
)
|
||||
|
||||
return {
|
||||
suggestedTierKey,
|
||||
currentTier,
|
||||
}
|
||||
}
|
||||
|
||||
const getPythLink = async (pythOraclePk: PublicKey) => {
|
||||
const pythClient = new PythHttpClient(connection, MAINNET_PYTH_PROGRAM)
|
||||
const pythAccounts = await pythClient.getData()
|
||||
|
@ -121,16 +168,6 @@ const Dashboard: NextPage = () => {
|
|||
}
|
||||
}, [banks.length])
|
||||
|
||||
useEffect(() => {
|
||||
const handleGetPriceImapcts = async () => {
|
||||
const [resp] = await Promise.all([getPriceImpacts()])
|
||||
setPriceImapcts(resp)
|
||||
}
|
||||
if (group) {
|
||||
handleGetPriceImapcts()
|
||||
}
|
||||
}, [connection, group])
|
||||
|
||||
return (
|
||||
<GovernancePageWrapper noStyles={true}>
|
||||
<div className="col-span-12 lg:col-span-8 lg:col-start-3">
|
||||
|
@ -171,7 +208,12 @@ const Dashboard: NextPage = () => {
|
|||
Collpase All
|
||||
</Button>
|
||||
</div>
|
||||
<h3 className="mb-3 mt-6 text-base text-th-fgd-3">Banks</h3>
|
||||
<h3 className="mb-3 mt-6 flex text-base text-th-fgd-3">
|
||||
<span>Banks</span>
|
||||
<span className="ml-auto">
|
||||
Current / <span className="text-th-success">Suggested</span>{' '}
|
||||
</span>
|
||||
</h3>
|
||||
<div className="border-b border-th-bkg-3">
|
||||
{banks
|
||||
.sort((a, b) => a.name.localeCompare(b.name))
|
||||
|
@ -185,6 +227,9 @@ const Dashboard: NextPage = () => {
|
|||
bank,
|
||||
)
|
||||
|
||||
const { currentTier, suggestedTierKey } =
|
||||
getSuggestedAndCurrentTier(bank)
|
||||
|
||||
return (
|
||||
<Disclosure key={bank.publicKey.toString()}>
|
||||
{({ open }) => (
|
||||
|
@ -203,11 +248,21 @@ const Dashboard: NextPage = () => {
|
|||
className="flex w-full items-center justify-between"
|
||||
aria-label="panel"
|
||||
>
|
||||
<div className="flex items-center">
|
||||
<div className="flex flex-1 items-center">
|
||||
<TokenLogo bank={bank} />
|
||||
<p className="ml-2 text-th-fgd-2">
|
||||
{formattedBankValues.name} Bank
|
||||
</p>
|
||||
<div className="ml-auto flex space-x-2">
|
||||
<div>{currentTier?.preset_name}</div>
|
||||
<div>/</div>
|
||||
<div className="text-th-success">
|
||||
{
|
||||
LISTING_PRESETS[suggestedTierKey]
|
||||
.preset_name
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ChevronDownIcon
|
||||
className={`${
|
||||
|
@ -486,17 +541,27 @@ const Dashboard: NextPage = () => {
|
|||
<div className="mb-4 mt-2 flex">
|
||||
<Button
|
||||
className=" ml-auto"
|
||||
onClick={() => setIsOpenSuggestionModal(true)}
|
||||
onClick={() =>
|
||||
setOpenedSuggestedModal(
|
||||
bank.mint.toBase58(),
|
||||
)
|
||||
}
|
||||
>
|
||||
Check suggested values
|
||||
{isOpenSuggestionModal && (
|
||||
{openedSuggestedModal ===
|
||||
bank.mint.toBase58() && (
|
||||
<DashboardSuggestedValues
|
||||
priceImpacts={priceImpacts}
|
||||
midPriceImp={midPriceImp}
|
||||
currentTier={currentTier}
|
||||
suggestedTierKey={suggestedTierKey}
|
||||
group={group}
|
||||
bank={bank}
|
||||
isOpen={isOpenSuggestionModal}
|
||||
isOpen={
|
||||
openedSuggestedModal ===
|
||||
bank.mint.toBase58()
|
||||
}
|
||||
onClose={() =>
|
||||
setIsOpenSuggestionModal(false)
|
||||
setOpenedSuggestedModal(null)
|
||||
}
|
||||
></DashboardSuggestedValues>
|
||||
)}
|
||||
|
|
|
@ -457,10 +457,9 @@ export type MidPriceImpact = Omit<
|
|||
'side' | 'min_price_impact_percent' | 'max_price_impact_percent'
|
||||
>
|
||||
|
||||
export const getPriceImpacts = async () => {
|
||||
const resp = await fetch(
|
||||
'https://api.mngo.cloud/data/v4/risk/listed-tokens-one-week-price-impacts',
|
||||
)
|
||||
const jsonReps = (await resp.json()) as PriceImpact[]
|
||||
return jsonReps
|
||||
export const getApiTokenName = (bankName: string) => {
|
||||
if (bankName === 'ETH (Portal)') {
|
||||
return 'ETH'
|
||||
}
|
||||
return bankName
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue