From f6ad6aed4d032bdf9da80bf9a23c8b2ecf76f022 Mon Sep 17 00:00:00 2001 From: Madalina Raicu Date: Wed, 26 Apr 2023 01:13:28 +0300 Subject: [PATCH] feat(oracles): add oracle full profile --- .../market-info/market-info-panels.tsx | 42 ++++-- libs/oracles/src/lib/components/index.ts | 1 + .../oracle-basic-profile.tsx | 30 ++-- .../components/oracle-full-profile/index.ts | 2 + .../oracle-full-profile.spec.tsx | 0 .../oracle-full-profile.stories.tsx | 41 ++++++ .../oracle-full-profile.tsx | 132 ++++++++++++++++++ .../src/components/dialog/dialog.tsx | 2 +- 8 files changed, 223 insertions(+), 27 deletions(-) create mode 100644 libs/oracles/src/lib/components/oracle-full-profile/index.ts create mode 100644 libs/oracles/src/lib/components/oracle-full-profile/oracle-full-profile.spec.tsx create mode 100644 libs/oracles/src/lib/components/oracle-full-profile/oracle-full-profile.stories.tsx create mode 100644 libs/oracles/src/lib/components/oracle-full-profile/oracle-full-profile.tsx diff --git a/libs/market-info/src/components/market-info/market-info-panels.tsx b/libs/market-info/src/components/market-info/market-info-panels.tsx index ccaccc984..24fb9a72f 100644 --- a/libs/market-info/src/components/market-info/market-info-panels.tsx +++ b/libs/market-info/src/components/market-info/market-info-panels.tsx @@ -1,4 +1,5 @@ import type { ComponentProps } from 'react'; +import { useState } from 'react'; import { useMemo } from 'react'; import { AssetDetailsTable, useAssetDataProvider } from '@vegaprotocol/assets'; import { t } from '@vegaprotocol/i18n'; @@ -6,7 +7,7 @@ import { totalFeesPercentage, marketDataProvider, } from '@vegaprotocol/market-list'; -import { ExternalLink, Splash } from '@vegaprotocol/ui-toolkit'; +import { Dialog, ExternalLink, Splash } from '@vegaprotocol/ui-toolkit'; import { addDecimalsFormatNumber, formatNumber, @@ -26,6 +27,7 @@ import { ConditionOperatorMapping } from '@vegaprotocol/types'; import { MarketTradingModeMapping } from '@vegaprotocol/types'; import { useEnvironment } from '@vegaprotocol/environment'; import type { Provider } from '@vegaprotocol/oracles'; +import { OracleProfileTitle, OracleFullProfile } from '@vegaprotocol/oracles'; import { OracleBasicProfile, useOracleProofs } from '@vegaprotocol/oracles'; import { useDataProvider } from '@vegaprotocol/react-helpers'; @@ -456,6 +458,11 @@ export const OracleInfoPanel = ({ const { VEGA_EXPLORER_URL, ORACLE_PROOFS_URL } = useEnvironment(); const { data } = useOracleProofs(ORACLE_PROOFS_URL); + const oracleId = + type === 'settlementData' + ? product.dataSourceSpecForSettlementData.id + : product.dataSourceSpecForTradingTermination.id; + return (
{type === 'settlementData' ? t('View settlement data specification') @@ -488,10 +492,12 @@ export const DataSourceProof = ({ data, providers, type, + id, }: { data: DataSourceDefinition; providers: Provider[] | undefined; type: 'settlementData' | 'termination'; + id: string; }) => { if (data.sourceType.__typename === 'DataSourceDefinitionExternal') { const signers = data.sourceType.sourceType.signers || []; @@ -509,7 +515,7 @@ export const DataSourceProof = ({ providers={providers} signer={signer} type={type} - index={i} + id={id} /> ); })} @@ -540,12 +546,14 @@ const OracleLink = ({ providers, signer, type, + id, }: { providers: Provider[]; signer: SignerKind; type: 'settlementData' | 'termination'; - index: number; + id: string; }) => { + const [dialogOpen, setDialogOpen] = useState(false); const signerProviders = providers.filter((p) => { if (signer.__typename === 'PubKey') { if ( @@ -575,10 +583,20 @@ const OracleLink = ({ return (
{signerProviders.map((provider) => ( - +
+ setDialogOpen(!dialogOpen)} + > + } + open={dialogOpen} + onChange={() => setDialogOpen(!dialogOpen)} + aria-labelledby="oracle-proof-dialog" + > + + +
))}
); diff --git a/libs/oracles/src/lib/components/index.ts b/libs/oracles/src/lib/components/index.ts index 8706f7f57..98884d206 100644 --- a/libs/oracles/src/lib/components/index.ts +++ b/libs/oracles/src/lib/components/index.ts @@ -1 +1,2 @@ export * from './oracle-basic-profile'; +export * from './oracle-full-profile'; diff --git a/libs/oracles/src/lib/components/oracle-basic-profile/oracle-basic-profile.tsx b/libs/oracles/src/lib/components/oracle-basic-profile/oracle-basic-profile.tsx index 38c08383f..2da066b35 100644 --- a/libs/oracles/src/lib/components/oracle-basic-profile/oracle-basic-profile.tsx +++ b/libs/oracles/src/lib/components/oracle-basic-profile/oracle-basic-profile.tsx @@ -1,10 +1,10 @@ import { t } from '@vegaprotocol/i18n'; import type { Provider } from '../../oracle-schema'; import { + ButtonLink, ExternalLink, Icon, Intent, - Link, VegaIcon, VegaIconNames, } from '@vegaprotocol/ui-toolkit'; @@ -12,7 +12,7 @@ import type { IconName } from '@blueprintjs/icons'; import { IconNames } from '@blueprintjs/icons'; import classNames from 'classnames'; -const getVerifiedStatusIcon = (provider: Provider) => { +export const getVerifiedStatusIcon = (provider: Provider) => { const getIconIntent = () => { switch (provider.oracle.status) { case 'GOOD': @@ -54,7 +54,13 @@ const getVerifiedStatusIcon = (provider: Provider) => { }; }; -export const OracleBasicProfile = ({ provider }: { provider: Provider }) => { +export const OracleBasicProfile = ({ + provider, + onClick, +}: { + provider: Provider; + onClick?: (value?: boolean) => void; +}) => { const { icon, message, intent } = getVerifiedStatusIcon(provider); const verifiedProofs = provider.proofs.filter( @@ -77,18 +83,14 @@ export const OracleBasicProfile = ({ provider }: { provider: Provider }) => { <> {provider.url && ( - - - {provider.name} - - ({verifiedProofs.length}) - + + onClick && onClick(true)}> + {provider.name} + + + ({verifiedProofs.length}) - + )} ( + +); + +export const OraclePrimary = Template.bind({}); + +OraclePrimary.args = { + provider: { + name: 'Test oracle', + url: 'https://zombo.com', + description_markdown: + 'Some markdown describing the oracle provider.\n\nTwitter: @FacesPics2\n', + oracle: { + status: 'GOOD', + status_reason: '', + first_verified: '2023-02-28T00:00:00.000Z', + last_verified: '2023-02-28T00:00:00.000Z', + type: 'eth_address', + eth_address: '0xfCEAdAFab14d46e20144F48824d0C09B1a03F2BC', + }, + proofs: [ + { + format: 'signed_message', + available: true, + type: 'eth_address', + eth_address: '0x949AF81E51D57831AE52591d17fBcdd1014a5f52', + message: 'SOMEHEX', + }, + ], + github_link: + 'https://github.com/vegaprotocol/well-known/blob/main/oracle-providers/eth_address-0xfCEAdAFab14d46e20144F48824d0C09B1a03F2BC.toml', + }, +}; diff --git a/libs/oracles/src/lib/components/oracle-full-profile/oracle-full-profile.tsx b/libs/oracles/src/lib/components/oracle-full-profile/oracle-full-profile.tsx new file mode 100644 index 000000000..3e4d123f4 --- /dev/null +++ b/libs/oracles/src/lib/components/oracle-full-profile/oracle-full-profile.tsx @@ -0,0 +1,132 @@ +import { t } from '@vegaprotocol/i18n'; +import type { Provider } from '../../oracle-schema'; +import { + ExternalLink, + Icon, + Intent, + VegaIcon, + VegaIconNames, +} from '@vegaprotocol/ui-toolkit'; +import type { IconName } from '@blueprintjs/icons'; +import classNames from 'classnames'; +import { getLinkIcon, getVerifiedStatusIcon } from '../oracle-basic-profile'; +import { useEnvironment } from '@vegaprotocol/environment'; + +export const OracleProfileTitle = ({ provider }: { provider: Provider }) => { + const { icon, intent } = getVerifiedStatusIcon(provider); + const verifiedProofs = provider.proofs.filter( + (proof) => proof.available === true + ); + return ( + + {provider.url && ( + + {provider.name} + + ({verifiedProofs.length}) + + + )} + + + + + ); +}; + +export const OracleFullProfile = ({ + provider, + id, +}: { + provider: Provider; + id: string; +}) => { + const { message } = getVerifiedStatusIcon(provider); + const { VEGA_EXPLORER_URL } = useEnvironment(); + + const signedProofs = provider.proofs.filter( + (proof) => proof.format === 'signed_message' && proof.available === true + ); + + const links = provider.proofs + .filter((proof) => proof.format === 'url' && proof.available === true) + .map((proof) => ({ + ...proof, + url: 'url' in proof ? proof.url : '', + icon: getLinkIcon(proof.type), + })); + + return ( +
+

+ {message} +

+ +
+
+

+ {t('%s verified accounts', links.length.toString())} +

+ {links.length > 0 ? ( +
+ {links.map((link) => ( + + + + + + {link.type}{' '} + + + + ))} +
+ ) : ( +

+ {t('This oracle has not proven ownership of any accounts.')} +

+ )} +
+
+

+ {t('Details')} +

+ {id && ( + + {t('Block explorer')} + + )} + {provider.github_link && ( + + {t('Oracle repository')} + + )} +
+
+ +
+

+ {t('Oracle in %s %s', [ + signedProofs.length.toString(), + signedProofs.length === 1 ? 'market' : 'markets', + ])} +

+
+
+ ); +}; diff --git a/libs/ui-toolkit/src/components/dialog/dialog.tsx b/libs/ui-toolkit/src/components/dialog/dialog.tsx index 21918b352..6e719beb9 100644 --- a/libs/ui-toolkit/src/components/dialog/dialog.tsx +++ b/libs/ui-toolkit/src/components/dialog/dialog.tsx @@ -13,7 +13,7 @@ interface DialogProps { onChange?: (isOpen: boolean) => void; onCloseAutoFocus?: (e: Event) => void; onInteractOutside?: (e: Event) => void; - title?: string; + title?: string | ReactNode; icon?: ReactNode; intent?: Intent; size?: 'small' | 'medium';