feat(trading): oracle banner check termination and settlement data oracles (#3707)

This commit is contained in:
m.ray 2023-05-16 16:12:22 +03:00 committed by GitHub
parent 1e9ff31fd7
commit 1a274a67c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 73 additions and 13 deletions

View File

@ -199,7 +199,6 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
.within(() => {
cy.getByTestId('block-explorer-link').contains('Block explorer');
cy.getByTestId('github-link').contains('Oracle repository');
cy.getByTestId('verified-accounts').contains('0 proofs of ownership');
});
cy.getByTestId('dialog-close').click();

View File

@ -25,14 +25,30 @@ export const oracleStatuses = {
export const OracleBanner = ({ marketId }: { marketId: string }) => {
const [open, onChange] = useState(false);
const oracle = useMarketOracle(marketId);
if (!oracle || oracle.provider.oracle.status === 'GOOD') {
return null;
const settlementOracle = useMarketOracle(marketId);
const tradingTerminationOracle = useMarketOracle(
marketId,
'dataSourceSpecForTradingTermination'
);
let maliciousOracle = null;
if (settlementOracle?.provider.oracle.status !== 'GOOD') {
maliciousOracle = settlementOracle;
} else if (tradingTerminationOracle?.provider.oracle.status !== 'GOOD') {
maliciousOracle = tradingTerminationOracle;
}
const { provider } = oracle;
if (!settlementOracle && !tradingTerminationOracle) {
return (
<NotificationBanner intent={Intent.Primary}>
<div>{t('There is no oracle for this market yet.')} </div>
</NotificationBanner>
);
}
if (!maliciousOracle) return null;
const { provider } = maliciousOracle;
return (
<>
<OracleDialog open={open} onChange={onChange} {...oracle} />
<OracleDialog open={open} onChange={onChange} {...maliciousOracle} />
<NotificationBanner intent={Intent.Danger}>
<div>
Oracle status for this market is{' '}

View File

@ -2,6 +2,7 @@ import { t } from '@vegaprotocol/i18n';
import type { Provider } from '../../oracle-schema';
import { MarketState, MarketStateMapping } from '@vegaprotocol/types';
import {
ButtonLink,
ExternalLink,
Icon,
Intent,
@ -15,6 +16,7 @@ import { getLinkIcon, getVerifiedStatusIcon } from '../oracle-basic-profile';
import { useEnvironment } from '@vegaprotocol/environment';
import type { OracleMarketSpecFieldsFragment } from '../../__generated__/OracleMarketsSpec';
import ReactMarkdown from 'react-markdown';
import { useState } from 'react';
export const OracleProfileTitle = ({ provider }: { provider: Provider }) => {
const { icon, intent } = getVerifiedStatusIcon(provider);
@ -78,6 +80,7 @@ export const OracleFullProfile = ({
}) => {
const { message } = getVerifiedStatusIcon(provider);
const { VEGA_EXPLORER_URL } = useEnvironment();
const [showMore, setShowMore] = useState(false);
const links = provider.proofs
.filter((proof) => proof.format === 'url' && proof.available === true)
@ -86,6 +89,9 @@ export const OracleFullProfile = ({
url: 'url' in proof ? proof.url : '',
icon: getLinkIcon(proof.type),
}));
const signedMessageProofs = provider.proofs.filter(
(proof) => proof.format === 'signed_message' && proof.available === true
);
return (
<div className="flex flex-col text-sm" data-testid="oracle-full-profile">
@ -103,8 +109,15 @@ export const OracleFullProfile = ({
disallowedElements={['img']}
linkTarget="_blank"
>
{provider.description_markdown}
{showMore
? provider.description_markdown
: provider.description_markdown.slice(0, 100) + '...'}
</ReactMarkdown>
<span>
<ButtonLink onClick={() => setShowMore(!showMore)}>
{!showMore ? t('Read more') : t('Show less')}
</ButtonLink>
</span>
</div>
</div>
<div className="grid grid-cols-2 gap-6">
@ -113,9 +126,12 @@ export const OracleFullProfile = ({
className="dark:text-vega-light-300 text-vega-dark-300 uppercase"
data-testid="verified-accounts"
>
{t('%s proofs of ownership', links.length.toString())}
{t('%s %s of ownership', [
provider.proofs.length.toString(),
provider.proofs.length === 1 ? 'proof' : 'proofs',
])}
</p>
{links.length > 0 ? (
{provider.proofs.length > 0 ? (
<div className="flex flex-col gap-1">
{links.map((link) => (
<ExternalLink
@ -132,6 +148,31 @@ export const OracleFullProfile = ({
</span>
</ExternalLink>
))}
{signedMessageProofs.length > 0 && (
<ExternalLink
key={'more-proofs'}
href={provider.github_link}
className="flex align-items-bottom underline text-sm pt-2"
>
{links.length > 0 ? (
<span className="underline">
{t('And %s more %s', [
signedMessageProofs.length.toString(),
signedMessageProofs.length === 1 ? 'proof' : 'proofs',
])}{' '}
<VegaIcon name={VegaIconNames.OPEN_EXTERNAL} size={13} />
</span>
) : (
<span className="underline">
{t('Verify %s %s of ownership', [
signedMessageProofs.length.toString(),
signedMessageProofs.length === 1 ? 'proof' : 'proofs',
])}{' '}
<VegaIcon name={VegaIconNames.OPEN_EXTERNAL} size={13} />
</span>
)}
</ExternalLink>
)}
</div>
) : (
<p className="dark:text-vega-light-300 text-vega-dark-300">

View File

@ -4,7 +4,12 @@ import { useDataProvider } from '@vegaprotocol/data-provider';
import { marketInfoProvider } from '../components/market-info/market-info-data-provider';
import { useMemo } from 'react';
export const useMarketOracle = (marketId: string) => {
export const useMarketOracle = (
marketId: string,
dataSourceSpecKey:
| 'dataSourceSpecForSettlementData'
| 'dataSourceSpecForTradingTermination' = 'dataSourceSpecForSettlementData'
) => {
const { ORACLE_PROOFS_URL } = useEnvironment();
const { data: marketInfo } = useDataProvider({
dataProvider: marketInfoProvider,
@ -16,8 +21,7 @@ export const useMarketOracle = (marketId: string) => {
return undefined;
}
const dataSourceSpec =
marketInfo.tradableInstrument.instrument.product
.dataSourceSpecForSettlementData;
marketInfo.tradableInstrument.instrument.product[dataSourceSpecKey];
const { data: dataSource, id: dataSourceSpecId } = dataSourceSpec;
const provider = data.find((provider) =>
provider.proofs.some((proof) => {
@ -48,5 +52,5 @@ export const useMarketOracle = (marketId: string) => {
return { provider, dataSourceSpecId };
}
return undefined;
}, [data, marketInfo]);
}, [data, dataSourceSpecKey, marketInfo]);
};