add oracle provider to market details modals

This commit is contained in:
saml33 2023-05-01 14:42:29 +10:00
parent 9d37cf2007
commit cf0a5e7e59
10 changed files with 122 additions and 29 deletions

View File

@ -3,6 +3,8 @@ import Modal from '../shared/Modal'
import { useTranslation } from 'next-i18next'
import { PerpMarket } from '@blockworks-foundation/mango-v4'
import Button from '@components/shared/Button'
import useOracleProvider from 'hooks/useOracleProvider'
import { ArrowTopRightOnSquareIcon } from '@heroicons/react/20/solid'
// import Tooltip from '@components/shared/Tooltip'
interface PerpMarketDetailsModalProps {
@ -17,6 +19,9 @@ const PerpMarketDetailsModal = ({
market,
}: ModalCombinedProps) => {
const { t } = useTranslation(['common', 'trade'])
const { oracleProvider, oracleLinkPath } = useOracleProvider()
console.log(oracleProvider, oracleLinkPath)
return market ? (
<Modal isOpen={isOpen} onClose={onClose}>
@ -62,6 +67,22 @@ const PerpMarketDetailsModal = ({
{(100 * market.maxFunding.toNumber()).toFixed(2)}%
</p>
</div>
<div className="flex justify-between">
<p>{t('trade:oracle')}</p>
{oracleLinkPath ? (
<a
className="flex items-center"
href={oracleLinkPath}
target="_blank"
rel="noopener noreferrer"
>
<span className="mr-1.5">{oracleProvider}</span>
<ArrowTopRightOnSquareIcon className="h-4 w-4" />
</a>
) : (
<p className="text-th-fgd-2">{oracleProvider}</p>
)}
</div>
{/* Uncomment when insurance fund is ready */}
{/* <div className="flex justify-between">
<Tooltip

View File

@ -4,6 +4,8 @@ import { useTranslation } from 'next-i18next'
import useSelectedMarket from 'hooks/useSelectedMarket'
import { Serum3Market } from '@blockworks-foundation/mango-v4'
import Button from '@components/shared/Button'
import useOracleProvider from 'hooks/useOracleProvider'
import { ArrowTopRightOnSquareIcon } from '@heroicons/react/20/solid'
// import useMangoGroup from 'hooks/useMangoGroup'
// import { useMemo } from 'react'
// import Tooltip from '@components/shared/Tooltip'
@ -23,6 +25,7 @@ const SpotMarketDetailsModal = ({
}: ModalCombinedProps) => {
const { t } = useTranslation(['common', 'trade'])
const { serumOrPerpMarket } = useSelectedMarket()
const { oracleProvider, oracleLinkPath } = useOracleProvider()
// const { group } = useMangoGroup()
// const [baseBank, quoteBank] = useMemo(() => {
@ -61,6 +64,22 @@ const SpotMarketDetailsModal = ({
<p>{t('trade:max-leverage')}</p>
<p className="font-mono text-th-fgd-2">5x</p>
</div>
<div className="flex justify-between">
<p>{t('trade:oracle')}</p>
{oracleLinkPath ? (
<a
className="flex items-center"
href={oracleLinkPath}
target="_blank"
rel="noopener noreferrer"
>
<span className="mr-1.5">{oracleProvider}</span>
<ArrowTopRightOnSquareIcon className="h-4 w-4" />
</a>
) : (
<p className="text-th-fgd-2">{oracleProvider}</p>
)}
</div>
{/* {baseMintInfo ? (
<div className="flex justify-between">
<Tooltip

View File

@ -7,11 +7,7 @@ import Tooltip from '@components/shared/Tooltip'
import { useTranslation } from 'next-i18next'
import mangoStore from '@store/mangoStore'
import { useEffect, useState } from 'react'
import {
PerpMarket,
Bank,
OracleProvider,
} from '@blockworks-foundation/mango-v4'
import { PerpMarket, Bank } from '@blockworks-foundation/mango-v4'
import { BorshAccountsCoder } from '@coral-xyz/anchor'
import {
floorToDecimal,
@ -21,6 +17,8 @@ import {
import dayjs from 'dayjs'
import duration from 'dayjs/plugin/duration'
import relativeTime from 'dayjs/plugin/relativeTime'
import useOracleProvider from 'hooks/useOracleProvider'
import { ArrowTopRightOnSquareIcon } from '@heroicons/react/20/solid'
const OraclePrice = ({
setChangePrice,
@ -38,10 +36,10 @@ const OraclePrice = ({
const connection = mangoStore((s) => s.connection)
const [price, setPrice] = useState(stalePrice)
const [oracleProviderName, setOracleProviderName] = useState('Unknown')
const [oracleLastUpdatedSlot, setOracleLastUpdatedSlot] = useState(0)
const [highestSlot, setHighestSlot] = useState(0)
const [isStale, setIsStale] = useState(false)
const { oracleProvider, oracleLinkPath } = useOracleProvider()
const { t } = useTranslation(['common', 'trade'])
@ -64,20 +62,6 @@ const OraclePrice = ({
decimals = group.getMintDecimals(baseBank.mint)
}
switch (marketOrBank.oracleProvider) {
case OracleProvider.Pyth:
setOracleProviderName('Pyth')
break
case OracleProvider.Switchboard:
setOracleProviderName('Switchboard')
break
case OracleProvider.Stub:
setOracleProviderName('Stub')
break
default:
setOracleProviderName('Unknown')
}
const coder = new BorshAccountsCoder(client.program.idl)
const subId = connection.onAccountChange(
marketOrBank.oracle,
@ -147,8 +131,21 @@ const OraclePrice = ({
placement="bottom"
content={
<>
<div>
{t('trade:price-provided-by')} {oracleProviderName}.
<div className="flex">
<span className="mr-1">{t('trade:price-provided-by')}</span>
{oracleLinkPath ? (
<a
href={oracleLinkPath}
target="_blank"
rel="noopener noreferrer"
className="flex items-center"
>
<span className="mr-1">{oracleProvider}</span>
<ArrowTopRightOnSquareIcon className="h-4 w-4" />
</a>
) : (
<span className="text-th-fgd-2">{oracleProvider}</span>
)}
</div>
<div className="mt-2">
{t('trade:last-updated')}{' '}

View File

@ -0,0 +1,51 @@
import {
Bank,
OracleProvider,
PerpMarket,
} from '@blockworks-foundation/mango-v4'
import { useMemo } from 'react'
import { formatTokenSymbol } from 'utils/tokens'
import useMangoGroup from './useMangoGroup'
import useSelectedMarket from './useSelectedMarket'
const useOracleProvider = () => {
const { selectedMarket } = useSelectedMarket()
const { group } = useMangoGroup()
const [oracleProvider, oracleLinkPath] = useMemo(() => {
if (!group || !selectedMarket) return ['', '']
let marketOrBank: PerpMarket | Bank
let name: string
if (selectedMarket instanceof PerpMarket) {
marketOrBank = selectedMarket
name = selectedMarket.name.split('-')[0]
} else {
const baseBank = group.getFirstBankByTokenIndex(
selectedMarket.baseTokenIndex
)
marketOrBank = baseBank
name = formatTokenSymbol(baseBank.name)
}
switch (marketOrBank.oracleProvider) {
case OracleProvider.Pyth:
return [
'Pyth',
`https://pyth.network/price-feeds/crypto-${name.toLowerCase()}-usd`,
]
case OracleProvider.Switchboard:
return [
'Switchboard',
`https://switchboard.xyz/explorer/3/${marketOrBank.oracle.toString()}`,
]
case OracleProvider.Stub:
return ['Stub', '']
default:
return ['Unknown', '']
}
}, [group, selectedMarket])
return { oracleProvider, oracleLinkPath }
}
export default useOracleProvider

View File

@ -41,6 +41,7 @@
"notional": "Notional",
"notional-volume": "Notional Volume ($)",
"open-interest": "Open Interest",
"oracle": "Oracle",
"oracle-not-updated": "This oracle has not updated recently.",
"oracle-not-updated-warning": "Actions will fail for accounts with a position in this token.",
"oracle-price": "Oracle Price",
@ -54,7 +55,7 @@
"post": "Post",
"preview-sound": "Preview Sound",
"price-expect": "The price you receive may be worse than you expect and full execution is not guaranteed. Max slippage is 2.5% for your safety. The part of your position with slippage beyond 2.5% will not be closed.",
"price-provided-by": "This price is provided by",
"price-provided-by": "Oracle by",
"quote": "Quote",
"reduce-only": "Reduce Only",
"sells": "Sells",

View File

@ -41,6 +41,7 @@
"notional": "Notional",
"notional-volume": "Notional Volume ($)",
"open-interest": "Open Interest",
"oracle": "Oracle",
"oracle-not-updated": "This oracle has not updated recently.",
"oracle-not-updated-warning": "Actions will fail for accounts with a position in this token.",
"oracle-price": "Oracle Price",
@ -54,7 +55,7 @@
"post": "Post",
"preview-sound": "Preview Sound",
"price-expect": "The price you receive may be worse than you expect and full execution is not guaranteed. Max slippage is 2.5% for your safety. The part of your position with slippage beyond 2.5% will not be closed.",
"price-provided-by": "This price is provided by",
"price-provided-by": "Oracle by",
"quote": "Quote",
"reduce-only": "Reduce Only",
"sells": "Sells",

View File

@ -41,6 +41,7 @@
"notional": "Notional",
"notional-volume": "Notional Volume ($)",
"open-interest": "Open Interest",
"oracle": "Oracle",
"oracle-not-updated": "This oracle has not updated recently.",
"oracle-not-updated-warning": "Actions will fail for accounts with a position in this token.",
"oracle-price": "Oracle Price",
@ -54,7 +55,7 @@
"post": "Post",
"preview-sound": "Preview Sound",
"price-expect": "The price you receive may be worse than you expect and full execution is not guaranteed. Max slippage is 2.5% for your safety. The part of your position with slippage beyond 2.5% will not be closed.",
"price-provided-by": "This price is provided by",
"price-provided-by": "Oracle by",
"quote": "Quote",
"reduce-only": "Reduce Only",
"sells": "Sells",

View File

@ -41,6 +41,7 @@
"notional": "Notional",
"notional-volume": "Notional Volume ($)",
"open-interest": "Open Interest",
"oracle": "Oracle",
"oracle-not-updated": "This oracle has not updated recently.",
"oracle-not-updated-warning": "Actions will fail for accounts with a position in this token.",
"oracle-price": "Oracle Price",
@ -54,7 +55,7 @@
"post": "Post",
"preview-sound": "Preview Sound",
"price-expect": "The price you receive may be worse than you expect and full execution is not guaranteed. Max slippage is 2.5% for your safety. The part of your position with slippage beyond 2.5% will not be closed.",
"price-provided-by": "This price is provided by",
"price-provided-by": "Oracle by",
"quote": "Quote",
"reduce-only": "Reduce Only",
"sells": "Sells",

View File

@ -41,6 +41,7 @@
"notional": "合約面值",
"notional-volume": "面值交易量($)",
"open-interest": "持倉量",
"oracle": "Oracle",
"oracle-not-updated": "This oracle has not updated recently.",
"oracle-not-updated-warning": "Actions will fail for accounts with a position in this token.",
"oracle-price": "預言機價格",
@ -54,7 +55,7 @@
"post": "Post",
"preview-sound": "聲音預覽",
"price-expect": "您收到的價格可能與您預期有差異,並且無法保證完全執行。為了您的安全,最大滑點保持為 2.5%。超過 2.5%滑點的部分不會被平倉。",
"price-provided-by": "This price is provided by",
"price-provided-by": "Oracle by",
"quote": "計價",
"reduce-only": "限減少",
"sells": "賣單",

View File

@ -142,8 +142,8 @@ export async function getNFTsByOwner(owner: PublicKey, connection: Connection) {
export const formatTokenSymbol = (symbol: string) => {
if (symbol.toLowerCase().includes('portal')) {
const truncSymbol = symbol.split(' ')[0]
return truncSymbol === 'WBTC' ? 'wBTC' : truncSymbol
const truncSymbol = symbol.split(' ')[0].toUpperCase()
return truncSymbol === 'WBTC' ? 'BTC' : truncSymbol
}
return symbol === 'MSOL' ? 'mSOL' : symbol
}