Skip to content

Commit

Permalink
Two sub-section risk summary (l2beat#5695)
Browse files Browse the repository at this point in the history
  • Loading branch information
sdlyy authored Nov 4, 2024
1 parent 0db74bd commit 5a3d0a0
Show file tree
Hide file tree
Showing 7 changed files with 226 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,43 +3,61 @@ import {
type DaLayer,
type ScalingProjectRisk,
} from '@l2beat/config'
import { type RiskSummarySectionProps } from '~/components/projects/sections/risk-summary-section'
import { type DaRiskSummarySectionProps } from '~/components/projects/sections/da-risk-summary-section'
import { type ProjectSectionProps } from '~/components/projects/sections/types'
import { groupRisks } from '~/utils/project/risk-summary/group-risks'

export function getDaProjectRiskSummarySection(
layer: DaLayer,
bridge: DaBridge,
isVerified: boolean,
): Omit<RiskSummarySectionProps, keyof ProjectSectionProps> {
const sections = [
): Omit<DaRiskSummarySectionProps, keyof ProjectSectionProps> {
const bridgeSections = [
{
id: 'contracts',
value:
bridge.type === 'OnChainBridge' || bridge.type === 'DAC'
? bridge.contracts
: { risks: [] },
},
{
id: 'da-layer-technology',
value: layer.technology,
},
{
id: 'da-bridge-technology',
value: bridge.technology,
},
]

const risks: (ScalingProjectRisk & { referencedId: string })[] = []
const layerSections = [
{
id: 'da-layer-technology',
value: layer.technology,
},
]

for (const { id, value } of sections) {
const layerRisks: (ScalingProjectRisk & { referencedId: string })[] = []

for (const { id, value } of layerSections) {
if (value.risks) {
layerRisks.push(...value.risks.map((x) => ({ ...x, referencedId: id })))
}
}

const bridgeRisks: (ScalingProjectRisk & { referencedId: string })[] = []

for (const { id, value } of bridgeSections) {
if (value.risks) {
risks.push(...value.risks.map((x) => ({ ...x, referencedId: id })))
bridgeRisks.push(...value.risks.map((x) => ({ ...x, referencedId: id })))
}
}

return {
riskGroups: groupRisks(risks),
layer: {
name: layer.display.name,
risks: groupRisks(layerRisks),
},
bridge: {
name: bridge.display.name,
risks: groupRisks(bridgeRisks),
},
warning: bridge.display.warning,
isVerified,
redWarning: undefined,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,9 +158,12 @@ export function getProjectDetails({

const items: ProjectDetailsSection[] = []

if (riskSummarySection.riskGroups.length > 0) {
if (
riskSummarySection.layer.risks.concat(riskSummarySection.bridge.risks)
.length > 0
) {
items.push({
type: 'RiskSummarySection',
type: 'DaRiskSummarySection',
props: {
id: 'risk-summary',
title: 'Risk summary',
Expand Down
9 changes: 9 additions & 0 deletions packages/frontend/src/components/projects/project-details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { cn } from '~/utils/cn'
import { ChartSection } from './sections/chart-section'
import { ContractsSection } from './sections/contracts/contracts-section'
import { MultiChainContractsSection } from './sections/contracts/multichain-contracts-section'
import { DaRiskSummarySection } from './sections/da-risk-summary-section'
import { DetailedDescriptionSection } from './sections/detailed-description-section'
import { GrissiniRiskAnalysisSection } from './sections/grissini-risk-analysis-section'
import { GroupSection } from './sections/group-section'
Expand Down Expand Up @@ -71,6 +72,14 @@ export function ProjectDetails(props: ProjectDetailsProps) {
{...item.props}
/>
)
case 'DaRiskSummarySection':
return (
<DaRiskSummarySection
key={item.props.id}
{...{ nested, sectionOrder }}
{...item.props}
/>
)
case 'RiskAnalysisSection':
return (
<RiskAnalysisSection
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { type Meta, type StoryObj } from '@storybook/react'
import { DaRiskSummarySection } from './da-risk-summary-section'
import { type RiskGroup } from './risk-summary-section'

const meta = {
title: 'Components/Projects/Sections/DA Risk Summary',
component: DaRiskSummarySection,
args: {
id: 'risk-analysis',
title: 'Risks summary',
sectionOrder: '1',
isVerified: true,
redWarning: undefined,
warning: undefined,
},
} satisfies Meta<typeof DaRiskSummarySection>
export default meta

type Story = StoryObj<typeof meta>

const risks: RiskGroup[] = [
{
name: 'Funds can be stolen if',
start: 1,
items: [
{
text: "a dishonest supermajority of Celestia validators finalizes an unavailable block, and there aren't light nodes on the network verifying data availability, or they fail at social signaling unavailable data.",
isCritical: true,
referencedId: '',
},
{
text: "a dishonest supermajority of Celestia validators finalizes an unavailable block, and there aren't light nodes on the network verifying data availability, or they fail at social signaling unavailable data.",
isCritical: true,
referencedId: '',
},
],
},
{
name: 'Funds can be frozen if',
start: 3,
items: [
{
text: 'the centralized validator goes down. Users cannot produce blocks themselves and exiting the system requires new block production.',
isCritical: true,
referencedId: '',
},
],
},
] as const

export const Default: Story = {
args: {
layer: {
name: 'DA Layer',
risks,
},
bridge: {
name: 'Bridge',
risks,
},
},
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { HorizontalSeparator } from '~/components/core/horizontal-separator'
import { WarningBar } from '~/components/warning-bar'
import { ShieldIcon } from '~/icons/shield'
import { UnverifiedIcon } from '~/icons/unverified'
import { ProjectSection } from './project-section'
import { EnumeratedRisks, type RiskGroup } from './risk-summary-section'
import { type ProjectSectionProps } from './types'

export interface DaRiskSummarySectionProps extends ProjectSectionProps {
layer: {
risks: RiskGroup[]
name: string
}
bridge: {
risks: RiskGroup[]
name: string
}
warning: string | undefined
isVerified: boolean | undefined
redWarning: string | undefined
}

export function DaRiskSummarySection({
layer,
bridge,
isVerified,
redWarning,
warning,
...sectionProps
}: DaRiskSummarySectionProps) {
if (layer.risks.concat(bridge.risks).length === 0) {
return null
}
return (
<ProjectSection {...sectionProps}>
{isVerified === false && (
<WarningBar
text="This project includes unverified contracts."
color="red"
isCritical={true}
className="mt-4"
icon={UnverifiedIcon}
/>
)}
{redWarning && (
<WarningBar
text={redWarning}
color="red"
className="mt-4"
icon={ShieldIcon}
/>
)}
{warning && (
<WarningBar
text={warning}
color="yellow"
isCritical={false}
className="mt-4"
/>
)}
{layer.risks.length > 0 && (
<div className="flex flex-col gap-2 ">
<span className="text-xs font-medium uppercase text-zinc-500 dark:text-gray-50">
{layer.name} risks
</span>
<EnumeratedRisks risks={layer.risks} />
</div>
)}
{layer.risks.length > 0 && bridge.risks.length > 0 && (
<HorizontalSeparator className="my-4 border-divider md:my-6" />
)}
{bridge.risks.length > 0 && (
<div className="flex flex-col gap-2">
<span className="text-xs font-medium uppercase text-zinc-500 dark:text-gray-50">
{bridge.name} risks
</span>
<EnumeratedRisks risks={bridge.risks} />
</div>
)}
</ProjectSection>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
import { WarningBar } from '~/components/warning-bar'
import { ShieldIcon } from '~/icons/shield'
import { UnverifiedIcon } from '~/icons/unverified'
import { cn } from '~/utils/cn'
import { ProjectSection } from './project-section'
import { type ProjectSectionProps } from './types'

Expand Down Expand Up @@ -68,34 +69,37 @@ export function RiskSummarySection({
className="mt-4"
/>
)}
{riskGroups.map((group, i) => (
<div className="mt-4 md:mt-6" key={i}>
<h3 className="font-bold text-red-300 md:text-lg">{group.name}</h3>
<ol
className="list-inside list-decimal p-1.5 text-gray-850 dark:text-gray-400"
start={group.start}
>
{group.items.map((item, i) => (
<li key={i}>
<a href={`#${item.referencedId}`} className="underline">
{item.isCritical ? (
<>
{item.text.slice(0, -1)}{' '}
<span className="text-red-300 underline">
{' '}
(CRITICAL)
</span>
{item.text.slice(-1)}
</>
) : (
item.text
)}
</a>
</li>
))}
</ol>
</div>
))}
<div className="mt-4 md:mt-6">
<EnumeratedRisks risks={riskGroups} />
</div>
</ProjectSection>
)
}

export function EnumeratedRisks({ risks }: { risks: RiskGroup[] }) {
return risks.map((group, i) => (
<div className={cn(i > 0 && 'mt-4 md:mt-6')} key={i}>
<h3 className="font-bold text-red-300 md:text-lg">{group.name}</h3>
<ol
className="list-inside list-decimal p-1.5 text-gray-850 dark:text-gray-400"
start={group.start}
>
{group.items.map((item, i) => (
<li key={i}>
<a href={`#${item.referencedId}`} className="underline">
{item.isCritical ? (
<>
{item.text.slice(0, -1)}{' '}
<span className="text-red-300 underline"> (CRITICAL)</span>
{item.text.slice(-1)}
</>
) : (
item.text
)}
</a>
</li>
))}
</ol>
</div>
))
}
7 changes: 7 additions & 0 deletions packages/frontend/src/components/projects/sections/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { type ChartSectionProps } from './chart-section'
import { type ContractsSectionProps } from './contracts/contracts-section'
import { type MultiChainContractsSectionProps } from './contracts/multichain-contracts-section'
import { type DaRiskSummarySectionProps } from './da-risk-summary-section'
import { type DetailedDescriptionSectionProps } from './detailed-description-section'
import { type GrissiniRiskAnalysisSectionProps } from './grissini-risk-analysis-section'
import { type GroupSectionProps } from './group-section'
Expand Down Expand Up @@ -70,6 +71,11 @@ export interface ProjectDetailsRiskSummarySection {
props: ProjectDetailsProps<RiskSummarySectionProps>
}

export interface ProjectDetailsDaRiskSummarySection {
type: 'DaRiskSummarySection'
props: ProjectDetailsProps<DaRiskSummarySectionProps>
}

export interface ProjectDetailsRiskAnalysisSection {
type: 'RiskAnalysisSection'
props: ProjectDetailsProps<RiskAnalysisSectionProps>
Expand Down Expand Up @@ -152,6 +158,7 @@ export type ProjectDetailsSection = {
| ProjectDetailsDetailedDescriptionSection
| ProjectDetailsMilestonesAndIncidentsSection
| ProjectDetailsRiskSummarySection
| ProjectDetailsDaRiskSummarySection
| ProjectDetailsRiskAnalysisSection
| L3ProjectDetailsRiskAnalysisSection
| ProjectDetailsStageSection
Expand Down

0 comments on commit 5a3d0a0

Please sign in to comment.