feat: add ui for internal data sources, add unit test

This commit is contained in:
Matthew Russell
2023-03-28 15:25:40 -07:00
parent 35b6ce3a14
commit d6b7cd3971
3 changed files with 181 additions and 11 deletions
@@ -0,0 +1,135 @@
import { render, screen } from '@testing-library/react';
import {
ConditionOperator,
ConditionOperatorMapping,
} from '@vegaprotocol/types';
import { DataSourceProof } from './market-info-panels';
describe('DataSourceProof', () => {
const ORACLE_PUBKEY =
'69464e35bcb8e8a2900ca0f87acaf252d50cf2ab2fc73694845a16b7c8a0dc6f';
it('renders correct proof for external data sources', () => {
const props = {
data: {
sourceType: {
__typename: 'DataSourceDefinitionExternal' as const,
sourceType: {
__typename: 'DataSourceSpecConfiguration' as const,
signers: [
{
__typename: 'Signer' as const,
signer: {
__typename: 'PubKey' as const,
key: ORACLE_PUBKEY,
},
},
],
},
},
},
providers: [
{
name: 'Another oracle',
url: 'https://zombo.com',
description_markdown:
'Some markdown describing the oracle provider.\n\nTwitter: @FacesPics2\n',
oracle: {
status: 'GOOD' as const,
status_reason: '',
first_verified: '2022-01-01T00:00:00.000Z',
last_verified: '2022-12-31T00:00:00.000Z',
type: 'public_key' as const,
public_key: ORACLE_PUBKEY,
},
proofs: [
{
format: 'signed_message' as const,
available: true,
type: 'public_key' as const,
public_key: ORACLE_PUBKEY,
message: 'SOMEHEX',
},
],
github_link: `https://github.com/vegaprotocol/well-known/blob/main/oracle-providers/PubKey-${ORACLE_PUBKEY}.toml`,
},
],
linkText: 'Termination proof',
};
render(<DataSourceProof {...props} />);
expect(screen.getByRole('link')).toHaveAttribute(
'href',
props.providers[0].github_link
);
});
it('renders message if no matching proof is found', () => {
const props = {
data: {
sourceType: {
__typename: 'DataSourceDefinitionExternal' as const,
sourceType: {
__typename: 'DataSourceSpecConfiguration' as const,
signers: [
{
__typename: 'Signer' as const,
signer: {
__typename: 'PubKey' as const,
key: ORACLE_PUBKEY,
},
},
],
},
},
},
providers: [],
linkText: 'Termination proof',
};
render(<DataSourceProof {...props} />);
expect(
screen.getByText('No oracle proof for data source')
).toBeInTheDocument();
});
it('renders message if no data source on market', () => {
const props = {
data: {
sourceType: {
__typename: 'Invalid',
},
},
providers: [],
linkText: 'Termination proof',
};
// @ts-ignore types are invalid
render(<DataSourceProof {...props} />);
expect(screen.getByText('Invalid data source')).toBeInTheDocument();
});
it('renders conditions for internal data sources', () => {
const condition = {
__typename: 'Condition' as const,
operator: ConditionOperator.OPERATOR_GREATER_THAN,
value: '100',
};
const props = {
data: {
sourceType: {
__typename: 'DataSourceDefinitionInternal' as const,
sourceType: {
__typename: 'DataSourceSpecConfigurationTime' as const,
conditions: [condition],
},
},
},
providers: [],
linkText: 'Termination proof',
};
render(<DataSourceProof {...props} />);
expect(screen.getByText('Internal conditions')).toBeInTheDocument();
expect(
screen.getByText(
`${ConditionOperatorMapping[condition.operator]} ${condition.value}`
)
).toBeInTheDocument();
});
});
@@ -22,6 +22,7 @@ import type {
} from './market-info-data-provider';
import BigNumber from 'bignumber.js';
import type { DataSourceDefinition, SignerKind } from '@vegaprotocol/types';
import { ConditionOperatorMapping } from '@vegaprotocol/types';
import { MarketTradingModeMapping } from '@vegaprotocol/types';
import { useEnvironment } from '@vegaprotocol/environment';
import type { Provider } from '@vegaprotocol/oracles';
@@ -418,10 +419,12 @@ export const OracleInfoPanel = ({
const product = market.tradableInstrument.instrument.product;
const { VEGA_EXPLORER_URL, ORACLE_PROOFS_URL } = useEnvironment();
const { data } = useOracleProofs(ORACLE_PROOFS_URL);
console.log(data);
return (
<MarketInfoTable data={product.dataSourceSpecBinding} {...props}>
<div className="flex flex-col gap-2 mt-4">
<div
className="flex flex-col gap-2 mt-4"
data-testid="oracle-proof-links"
>
<DataSourceProof
data={product.dataSourceSpecForSettlementData.data}
providers={data}
@@ -449,7 +452,7 @@ export const OracleInfoPanel = ({
);
};
const DataSourceProof = ({
export const DataSourceProof = ({
data,
providers,
linkText,
@@ -458,19 +461,25 @@ const DataSourceProof = ({
providers: Provider[] | undefined;
linkText: string;
}) => {
if (!providers) return null;
if (data.sourceType.__typename === 'DataSourceDefinitionExternal') {
const signers = data.sourceType.sourceType.signers || [];
if (!providers) {
return <p>{t('No oracle proofs found')}</p>;
}
return (
<div className="flex flex-col gap-2" data-testid="oracle-proof-links">
<div className="flex flex-col gap-2">
{signers.map(({ signer }, i) => {
return (
<OracleLink
key={i}
providers={providers}
signer={signer}
linkText={linkText}
// render link text with a number for the signer eg "View termination proof (1)"
linkText={
signers.length > 1 ? `${linkText} (${i + 1})` : linkText
}
/>
);
})}
@@ -479,10 +488,22 @@ const DataSourceProof = ({
}
if (data.sourceType.__typename === 'DataSourceDefinitionInternal') {
return <div>{data.sourceType.__typename}: Render internal conditions</div>;
return (
<div>
<h3>{t('Internal conditions')}</h3>
{data.sourceType.sourceType.conditions.map((condition, i) => {
if (!condition) return null;
return (
<p key={i}>
{ConditionOperatorMapping[condition.operator]} {condition.value}
</p>
);
})}
</div>
);
}
return <div>{t('No data sources')}</div>;
return <div>{t('Invalid data source')}</div>;
};
const OracleLink = ({
@@ -517,8 +538,12 @@ const OracleLink = ({
});
if (!provider) {
return <p>{t('No oracle found for data source')}</p>;
return <p>{t('No oracle proof for data source')}</p>;
}
return <ExternalLink href={provider.github_link}>{linkText}</ExternalLink>;
return (
<p>
<ExternalLink href={provider.github_link}>{linkText}</ExternalLink>
</p>
);
};
+10
View File
@@ -1,3 +1,4 @@
import type { ConditionOperator } from './__generated__/types';
import type {
AccountType,
AuctionTrigger,
@@ -22,6 +23,7 @@ import type {
VoteValue,
WithdrawalStatus,
DispatchMetric,
Condition,
} from './__generated__/types';
export const AccountTypeMapping: {
@@ -458,3 +460,11 @@ export const PositionStatusMapping: {
POSITION_STATUS_ORDERS_CLOSED: 'Maintained by network',
POSITION_STATUS_UNSPECIFIED: 'Normal',
};
export const ConditionOperatorMapping: { [C in ConditionOperator]: string } = {
OPERATOR_EQUALS: 'Equals',
OPERATOR_GREATER_THAN: 'Greater than',
OPERATOR_GREATER_THAN_OR_EQUAL: 'Greater than or equal to',
OPERATOR_LESS_THAN: 'Less than',
OPERATOR_LESS_THAN_OR_EQUAL: 'Less than or equal to',
};