From c5dd4a0e82db458daed22890d56e60cd2b278df4 Mon Sep 17 00:00:00 2001 From: Riordan Panayides Date: Thu, 27 Apr 2023 17:23:18 +0100 Subject: [PATCH] Add warning state if oracle is stale, convert last updated to human readable format --- components/trade/OraclePrice.tsx | 58 +++++++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 5 deletions(-) diff --git a/components/trade/OraclePrice.tsx b/components/trade/OraclePrice.tsx index 7a7c26a0..611d6686 100644 --- a/components/trade/OraclePrice.tsx +++ b/components/trade/OraclePrice.tsx @@ -1,4 +1,7 @@ -import { InformationCircleIcon } from '@heroicons/react/24/outline' +import { + ExclamationTriangleIcon, + InformationCircleIcon, +} from '@heroicons/react/24/outline' import useSelectedMarket from 'hooks/useSelectedMarket' import Tooltip from '@components/shared/Tooltip' import { useTranslation } from 'next-i18next' @@ -15,6 +18,9 @@ import { formatCurrencyValue, getDecimalCount, } from 'utils/numbers' +import dayjs from 'dayjs' +import duration from 'dayjs/plugin/duration' +import relativeTime from 'dayjs/plugin/relativeTime' const OraclePrice = () => { const { @@ -23,10 +29,16 @@ const OraclePrice = () => { selectedMarket, quoteBank, } = useSelectedMarket() + dayjs.extend(duration) + dayjs.extend(relativeTime) + 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 { t } = useTranslation(['common', 'trade']) //subscribe to the market oracle account @@ -65,7 +77,7 @@ const OraclePrice = () => { const coder = new BorshAccountsCoder(client.program.idl) const subId = connection.onAccountChange( marketOrBank.oracle, - async (info, _context) => { + async (info, context) => { // selectedMarket = mangoStore.getState().selectedMarket.current // if (!(selectedMarket instanceof PerpMarket)) return const { price, uiPrice, lastUpdatedSlot } = @@ -80,6 +92,22 @@ const OraclePrice = () => { marketOrBank._uiPrice = uiPrice marketOrBank._oracleLastUpdatedSlot = lastUpdatedSlot setOracleLastUpdatedSlot(lastUpdatedSlot) + + const marketSlot = mangoStore.getState().selectedMarket.lastSeenSlot + const oracleWriteSlot = context.slot + const accountSlot = mangoStore.getState().mangoAccount.lastSlot + const highestSlot = Math.max( + marketSlot.bids, + marketSlot.asks, + oracleWriteSlot, + accountSlot + ) + setHighestSlot(highestSlot) + setIsStale( + highestSlot - lastUpdatedSlot > + marketOrBank.oracleConfig.maxStalenessSlots.toNumber() + ) + if (selectedMarket instanceof PerpMarket) { setPrice(uiPrice) } else { @@ -108,10 +136,26 @@ const OraclePrice = () => { <>
-
This price is provided by {oracleProviderName}
-
Last updated at slot {oracleLastUpdatedSlot}
+
This price is provided by {oracleProviderName}.
+
+ Last updated{' '} + {dayjs + .duration({ + seconds: -((highestSlot - oracleLastUpdatedSlot) * 0.5), + }) + .humanize(true)} + . +
+ {isStale ? ( +
+ This oracle has not updated recently. +
+ Actions will fail for accounts with a position in this token. +
+ ) : undefined} } > @@ -119,7 +163,11 @@ const OraclePrice = () => {
{t('trade:oracle-price')}
- + {isStale ? ( + + ) : ( + + )}