- {/* Header with title and risk level */}
-
+
+
+
+
+
+
- {/* Description paragraphs */}
- {descriptionArray.map((paragraph, index) => (
-
- {paragraph}
-
- ))}
-
- {/* Requirements section with divider */}
- {requirements.length > 0 && (
-
- {/* Thin divider line */}
-
-
-
- {`//`} REQUIREMENTS
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{requirements.map((requirement, index) => (
- -
- {iconsMapping[requirement.riskLevel]}
-
- {requirement.name}
-
-
+
))}
-
- )}
+
+
);
diff --git a/apps/dashboard/features/risk-analysis/hooks/useRiskAreaData.ts b/apps/dashboard/features/risk-analysis/hooks/useRiskAreaData.ts
new file mode 100644
index 000000000..41c0314bf
--- /dev/null
+++ b/apps/dashboard/features/risk-analysis/hooks/useRiskAreaData.ts
@@ -0,0 +1,44 @@
+import { DaoIdEnum } from "@/shared/types/daos";
+import { getDaoRiskAreas } from "@/shared/utils/risk-analysis";
+import { JSX, ReactNode, useMemo } from "react";
+import { RiskAreaDisplayItem } from "../RiskAnalysisSection";
+import { RiskAreaEnum } from "@/shared/types/enums";
+
+const customizeGovRiskArea = (
+ riskAreas: RiskAreaDisplayItem[],
+ content?: JSX.Element,
+): RiskAreaDisplayItem[] => {
+ const customized = [...riskAreas];
+ const govIndex = customized.findIndex(
+ (risk) => risk.name === RiskAreaEnum.GOV_FRONTEND_RESILIENCE,
+ );
+
+ if (govIndex !== -1) {
+ customized[govIndex] = {
+ ...customized[govIndex],
+ content,
+ };
+ }
+
+ return customized;
+};
+
+export const useRiskAreaData = (daoId: DaoIdEnum, content?: JSX.Element) => {
+ const daoRiskAreas = useMemo(() => getDaoRiskAreas(daoId), [daoId]);
+
+ const riskAreasWithLevel: RiskAreaDisplayItem[] = useMemo(
+ () =>
+ Object.entries(daoRiskAreas).map(([name, info]) => ({
+ name,
+ level: info.riskLevel,
+ })),
+ [daoRiskAreas],
+ );
+
+ const customizedRiskAreas = useMemo(
+ () => customizeGovRiskArea(riskAreasWithLevel, content),
+ [riskAreasWithLevel, content],
+ );
+
+ return { daoRiskAreas, customizedRiskAreas };
+};
diff --git a/apps/dashboard/features/risk-analysis/utils/createRequirementsFromMetrics.ts b/apps/dashboard/features/risk-analysis/utils/createRequirementsFromMetrics.ts
new file mode 100644
index 000000000..7bfc422ba
--- /dev/null
+++ b/apps/dashboard/features/risk-analysis/utils/createRequirementsFromMetrics.ts
@@ -0,0 +1,22 @@
+import { DaoIdEnum } from "@/shared/types/daos";
+import { RiskAreaEnum, RiskLevel } from "@/shared/types/enums";
+import daoConfigByDaoId from "@/shared/dao-config";
+import { RequirementMetric } from "@/features/risk-analysis/components/RiskDescription";
+import { RISK_AREAS } from "@/shared/constants/risk-areas";
+
+export const createRequirementsFromMetrics = (
+ riskArea: RiskAreaEnum,
+ daoId: DaoIdEnum,
+): RequirementMetric[] => {
+ const daoConfig = daoConfigByDaoId[daoId];
+ const govImplItems = RISK_AREAS[riskArea].requirements;
+
+ return govImplItems.map((metricEnum) => {
+ const field = daoConfig.governanceImplementation?.fields?.[metricEnum];
+ return {
+ name: metricEnum,
+ riskLevel: field?.riskLevel || RiskLevel.NONE,
+ description: field?.description || "",
+ };
+ });
+};
diff --git a/apps/dashboard/features/risk-analysis/utils/getSelectedMetricData.ts b/apps/dashboard/features/risk-analysis/utils/getSelectedMetricData.ts
new file mode 100644
index 000000000..5f01a2992
--- /dev/null
+++ b/apps/dashboard/features/risk-analysis/utils/getSelectedMetricData.ts
@@ -0,0 +1,31 @@
+import { DaoIdEnum } from "@/shared/types/daos";
+import daoConfigByDaoId from "@/shared/dao-config";
+import { GovernanceImplementationEnum } from "@/shared/types/enums";
+import { GovernanceImplementationField } from "@/shared/dao-config/types";
+import { RequirementMetric } from "@/features/risk-analysis/components/RiskDescription";
+
+interface SelectedMetricData extends GovernanceImplementationField {
+ name: string;
+}
+export const getSelectedMetricData = (
+ metric: RequirementMetric | null,
+ daoId: DaoIdEnum,
+): SelectedMetricData | null => {
+ if (!metric) return null;
+
+ const daoConfig = daoConfigByDaoId[daoId];
+ const metricEnum = metric.name as GovernanceImplementationEnum;
+ const field = daoConfig.governanceImplementation?.fields?.[metricEnum];
+
+ if (!field) return null;
+
+ return {
+ name: metric.name,
+ description: field.description,
+ riskLevel: metric.riskLevel,
+ currentSetting: field.currentSetting,
+ impact: field.impact,
+ recommendedSetting: field.recommendedSetting,
+ nextStep: field.nextStep,
+ };
+};
diff --git a/apps/dashboard/shared/components/cards/RiskAreaCard.tsx b/apps/dashboard/shared/components/cards/RiskAreaCard.tsx
index 050beb397..5125d79b6 100644
--- a/apps/dashboard/shared/components/cards/RiskAreaCard.tsx
+++ b/apps/dashboard/shared/components/cards/RiskAreaCard.tsx
@@ -109,7 +109,7 @@ const RiskAreaCardInternal = ({
>
),
[RiskAreaCardEnum.RISK_ANALYSIS]: (
-
+
-
+
{isActive && (
)}
@@ -365,14 +365,14 @@ export const RiskAreaCardWrapper = ({
openInNewTab={false}
className="text-primary border-border-contrast hover:border-primary border-b border-dashed font-mono text-[13px] font-medium tracking-wider"
>
- RISK AREAS
+ ATTACK EXPOSURE
))}
{riskAreas.map((risk: RiskArea, index: number) => {
- if (risk.name === RiskAreaEnum.ATTACK_PROFITABILITY) {
+ if (risk.name === RiskAreaEnum.ECONOMIC_SECURITY) {
const daoIdEnum = daoId?.toUpperCase() as DaoIdEnum;
const daoConstants = daoConfig[daoIdEnum];
const riskValue = !daoConstants?.attackProfitability
diff --git a/apps/dashboard/shared/components/cards/RiskLevelCardSmall.tsx b/apps/dashboard/shared/components/cards/RiskLevelCardSmall.tsx
index 26dd86c9f..66c3c28bf 100644
--- a/apps/dashboard/shared/components/cards/RiskLevelCardSmall.tsx
+++ b/apps/dashboard/shared/components/cards/RiskLevelCardSmall.tsx
@@ -50,16 +50,11 @@ const RiskLabel = ({
}) => (
{status ?? "------"}
{icon}
-
- {icon}
-
);
diff --git a/apps/dashboard/shared/components/design-system/drawer/Drawer.tsx b/apps/dashboard/shared/components/design-system/drawer/Drawer.tsx
new file mode 100644
index 000000000..988862156
--- /dev/null
+++ b/apps/dashboard/shared/components/design-system/drawer/Drawer.tsx
@@ -0,0 +1,75 @@
+"use client";
+
+import * as React from "react";
+import { Drawer as DrawerPrimitive } from "vaul";
+import { useScreenSize } from "@/shared/hooks";
+import { cn } from "@/shared/utils";
+import type { DrawerRootProps } from "@/shared/components/design-system/drawer/types";
+
+const DrawerRoot = ({ open, onOpenChange, children }: DrawerRootProps) => {
+ const { isMobile } = useScreenSize();
+
+ return (
+
+ {children}
+
+ );
+};
+
+const DrawerPortal = ({
+ ...props
+}: React.ComponentProps
) => {
+ return ;
+};
+
+const DrawerOverlay = ({
+ className,
+ ...props
+}: React.ComponentProps) => {
+ return (
+
+ );
+};
+
+const DrawerContent = ({
+ className,
+ children,
+ ...props
+}: React.ComponentProps) => {
+ return (
+
+
+
+
+
+ {children}
+
+
+
+ );
+};
+
+export { DrawerRoot, DrawerContent, DrawerPortal, DrawerOverlay };
diff --git a/apps/dashboard/shared/components/design-system/drawer/components/DrawerBody.tsx b/apps/dashboard/shared/components/design-system/drawer/components/DrawerBody.tsx
new file mode 100644
index 000000000..e1299f5a4
--- /dev/null
+++ b/apps/dashboard/shared/components/design-system/drawer/components/DrawerBody.tsx
@@ -0,0 +1,14 @@
+"use client";
+
+import { cn } from "@/shared/utils";
+import type { DrawerBodyProps } from "@/shared/components/design-system/drawer/types";
+
+export const DrawerBody = ({ children, className }: DrawerBodyProps) => {
+ return (
+
+ {children}
+
+ );
+};
diff --git a/apps/dashboard/shared/components/design-system/drawer/components/DrawerCloseButton.tsx b/apps/dashboard/shared/components/design-system/drawer/components/DrawerCloseButton.tsx
new file mode 100644
index 000000000..6a7e71772
--- /dev/null
+++ b/apps/dashboard/shared/components/design-system/drawer/components/DrawerCloseButton.tsx
@@ -0,0 +1,9 @@
+"use client";
+
+import { X } from "lucide-react";
+import { IconButton } from "@/shared/components";
+import type { DrawerCloseButtonProps } from "@/shared/components/design-system/drawer/types";
+
+export const DrawerCloseButton = ({ onClick }: DrawerCloseButtonProps) => {
+ return ;
+};
diff --git a/apps/dashboard/shared/components/design-system/drawer/components/DrawerHeader.tsx b/apps/dashboard/shared/components/design-system/drawer/components/DrawerHeader.tsx
new file mode 100644
index 000000000..639c1b5cb
--- /dev/null
+++ b/apps/dashboard/shared/components/design-system/drawer/components/DrawerHeader.tsx
@@ -0,0 +1,35 @@
+"use client";
+
+import { DrawerSubtitle } from "@/shared/components/design-system/drawer/components/DrawerSubtitle";
+import { DrawerTitle } from "@/shared/components/design-system/drawer/components/DrawerTitle";
+import { DrawerCloseButton } from "@/shared/components/design-system/drawer/components/DrawerCloseButton";
+import { DrawerTabs } from "@/shared/components/design-system/drawer/components/DrawerTabs";
+import type { DrawerHeaderProps } from "@/shared/components/design-system/drawer/types";
+
+export const DrawerHeader = ({
+ subtitle,
+ title,
+ onClose,
+ tabs,
+ activeTab,
+ onTabChange,
+}: DrawerHeaderProps) => {
+ return (
+
+
+
+ {subtitle}
+ {title}
+
+
+
+ {tabs && activeTab && onTabChange && (
+
+ )}
+
+ );
+};
diff --git a/apps/dashboard/shared/components/design-system/drawer/components/DrawerSubtitle.tsx b/apps/dashboard/shared/components/design-system/drawer/components/DrawerSubtitle.tsx
new file mode 100644
index 000000000..6ca63a2ab
--- /dev/null
+++ b/apps/dashboard/shared/components/design-system/drawer/components/DrawerSubtitle.tsx
@@ -0,0 +1,11 @@
+"use client";
+
+import type { DrawerSubtitleProps } from "@/shared/components/design-system/drawer/types";
+
+export const DrawerSubtitle = ({ children }: DrawerSubtitleProps) => {
+ return (
+
+ {children}
+
+ );
+};
diff --git a/apps/dashboard/shared/components/design-system/drawer/components/DrawerTabs.tsx b/apps/dashboard/shared/components/design-system/drawer/components/DrawerTabs.tsx
new file mode 100644
index 000000000..94b924b19
--- /dev/null
+++ b/apps/dashboard/shared/components/design-system/drawer/components/DrawerTabs.tsx
@@ -0,0 +1,36 @@
+"use client";
+
+import { Tabs, TabsList, TabsTrigger } from "@radix-ui/react-tabs";
+import { cn } from "@/shared/utils";
+import type { DrawerTabsProps } from "@/shared/components/design-system/drawer/types";
+
+export const DrawerTabs = ({
+ tabs,
+ activeTab,
+ onTabChange,
+}: DrawerTabsProps) => {
+ return (
+
+
+ {tabs.map((tab) => (
+
+ {tab.label}
+
+ ))}
+
+
+ );
+};
diff --git a/apps/dashboard/shared/components/design-system/drawer/components/DrawerTitle.tsx b/apps/dashboard/shared/components/design-system/drawer/components/DrawerTitle.tsx
new file mode 100644
index 000000000..1cd84e0e7
--- /dev/null
+++ b/apps/dashboard/shared/components/design-system/drawer/components/DrawerTitle.tsx
@@ -0,0 +1,17 @@
+"use client";
+
+import type { DrawerTitleProps } from "@/shared/components/design-system/drawer/types";
+
+export const DrawerTitle = ({ children }: DrawerTitleProps) => {
+ if (typeof children === "string") {
+ return (
+
+ {children}
+
+ );
+ }
+
+ return (
+ {children}
+ );
+};
diff --git a/apps/dashboard/shared/components/design-system/drawer/index.ts b/apps/dashboard/shared/components/design-system/drawer/index.ts
new file mode 100644
index 000000000..52ef7f90f
--- /dev/null
+++ b/apps/dashboard/shared/components/design-system/drawer/index.ts
@@ -0,0 +1,21 @@
+export {
+ DrawerRoot,
+ DrawerContent,
+} from "@/shared/components/design-system/drawer/Drawer";
+export { DrawerHeader } from "@/shared/components/design-system/drawer/components/DrawerHeader";
+export { DrawerSubtitle } from "@/shared/components/design-system/drawer/components/DrawerSubtitle";
+export { DrawerTitle } from "@/shared/components/design-system/drawer/components/DrawerTitle";
+export { DrawerTabs } from "@/shared/components/design-system/drawer/components/DrawerTabs";
+export { DrawerBody } from "@/shared/components/design-system/drawer/components/DrawerBody";
+export { DrawerCloseButton } from "@/shared/components/design-system/drawer/components/DrawerCloseButton";
+
+export type {
+ DrawerRootProps,
+ DrawerHeaderProps,
+ DrawerSubtitleProps,
+ DrawerTitleProps,
+ DrawerTabConfig,
+ DrawerTabsProps,
+ DrawerBodyProps,
+ DrawerCloseButtonProps,
+} from "@/shared/components/design-system/drawer/types";
diff --git a/apps/dashboard/shared/components/design-system/drawer/types.ts b/apps/dashboard/shared/components/design-system/drawer/types.ts
new file mode 100644
index 000000000..e65df02f4
--- /dev/null
+++ b/apps/dashboard/shared/components/design-system/drawer/types.ts
@@ -0,0 +1,45 @@
+import { ReactNode } from "react";
+
+export interface DrawerRootProps {
+ open: boolean;
+ onOpenChange: (open: boolean) => void;
+ children: ReactNode;
+}
+
+export interface DrawerHeaderProps {
+ subtitle: string;
+ title: string | ReactNode;
+ onClose: () => void;
+ tabs?: DrawerTabConfig[];
+ activeTab?: string;
+ onTabChange?: (tabId: string) => void;
+}
+
+export interface DrawerSubtitleProps {
+ children: string;
+}
+
+export interface DrawerTitleProps {
+ children: string | ReactNode;
+}
+
+export interface DrawerTabConfig {
+ id: string;
+ label: string;
+ content: ReactNode;
+}
+
+export interface DrawerTabsProps {
+ tabs: DrawerTabConfig[];
+ activeTab: string;
+ onTabChange: (tabId: string) => void;
+}
+
+export interface DrawerBodyProps {
+ children: ReactNode;
+ className?: string;
+}
+
+export interface DrawerCloseButtonProps {
+ onClick: () => void;
+}
diff --git a/apps/dashboard/shared/components/index.ts b/apps/dashboard/shared/components/index.ts
index 97a88caba..3399ca618 100644
--- a/apps/dashboard/shared/components/index.ts
+++ b/apps/dashboard/shared/components/index.ts
@@ -33,5 +33,6 @@ export * from "@/shared/components/design-system/ActivityIndicator";
export * from "@/shared/components/design-system/buttons/button/Button";
export * from "@/shared/components/design-system/buttons/icon-button/IconButton";
export * from "@/shared/components/design-system/help-popover";
+export * from "@/shared/components/design-system/drawer";
export { StagesCardRequirements } from "@/shared/components/cards/StagesCardRequirements";
diff --git a/apps/dashboard/shared/components/ui/drawer.tsx b/apps/dashboard/shared/components/ui/drawer.tsx
deleted file mode 100644
index 2f7938730..000000000
--- a/apps/dashboard/shared/components/ui/drawer.tsx
+++ /dev/null
@@ -1,135 +0,0 @@
-"use client";
-
-import * as React from "react";
-import { Drawer as DrawerPrimitive } from "vaul";
-
-import { cn } from "@/shared/utils";
-
-function Drawer({
- ...props
-}: React.ComponentProps) {
- return ;
-}
-
-function DrawerTrigger({
- ...props
-}: React.ComponentProps) {
- return ;
-}
-
-function DrawerPortal({
- ...props
-}: React.ComponentProps) {
- return ;
-}
-
-function DrawerClose({
- ...props
-}: React.ComponentProps) {
- return ;
-}
-
-function DrawerOverlay({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- );
-}
-
-function DrawerContent({
- className,
- children,
- ...props
-}: React.ComponentProps) {
- return (
-
-
-
-
- {children}
-
-
- );
-}
-
-function DrawerHeader({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- );
-}
-
-function DrawerFooter({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- );
-}
-
-function DrawerTitle({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- );
-}
-
-function DrawerDescription({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- );
-}
-
-export {
- Drawer,
- DrawerPortal,
- DrawerOverlay,
- DrawerTrigger,
- DrawerClose,
- DrawerContent,
- DrawerHeader,
- DrawerFooter,
- DrawerTitle,
- DrawerDescription,
-};
diff --git a/apps/dashboard/shared/constants/governance-implementations.ts b/apps/dashboard/shared/constants/governance-implementations.ts
index 6c7c79cdb..fda678323 100644
--- a/apps/dashboard/shared/constants/governance-implementations.ts
+++ b/apps/dashboard/shared/constants/governance-implementations.ts
@@ -24,10 +24,6 @@ export const GOVERNANCE_IMPLEMENTATION_CONSTANTS = {
description:
"Allow for any user to cancel the proposer of an address if that address no longer holds the necessary voting power to pass proposal threshold while their proposal is still active.",
},
- [GovernanceImplementationEnum.PROPOSAL_THRESHOLD_CANCEL]: {
- description:
- "Whether a proposal may be canceled if the wallet that submitted it no longer has the number of governance tokens required to reach the proposal threshold.",
- },
[GovernanceImplementationEnum.SECURITY_COUNCIL]: {
description:
"Group of people responsible for taking action to increase the DAO's security against harmful proposals through a multisig administered by them.",
diff --git a/apps/dashboard/shared/constants/pages-constants.ts b/apps/dashboard/shared/constants/pages-constants.ts
index 633f5caf4..cf43c6e4e 100644
--- a/apps/dashboard/shared/constants/pages-constants.ts
+++ b/apps/dashboard/shared/constants/pages-constants.ts
@@ -41,14 +41,11 @@ export const PAGES_CONSTANTS = {
subDescription:
"When combined, these requirements determine the risk level of each area above. Here, you can explore each one individually and see why it's considered high risk—or not.",
},
- riskAnalysis: {
- title: "Risk Analysis",
+ attackExposure: {
+ title: "Attack Exposure",
page: "risk-analysis",
description:
- "Assess critical vulnerabilities in the DAO's governance setup.",
- subTitle: "Risk Areas",
- subDescription:
- "Each item highlights a specific risk area, showing which issues are resolved and which still expose the system to threats.",
+ "Core safeguards determine a DAO’s exposure to governance attacks. Overall defense risk is set by the weakest metric, where higher risk signals greater attack feasibility and impact.",
},
resilienceStages: {
title: "Resilience Stages",
diff --git a/apps/dashboard/shared/constants/recommended-settings.ts b/apps/dashboard/shared/constants/recommended-settings.ts
new file mode 100644
index 000000000..0d5acf42d
--- /dev/null
+++ b/apps/dashboard/shared/constants/recommended-settings.ts
@@ -0,0 +1,64 @@
+/**
+ * @file recommended-settings.ts
+ * Universal recommended settings for governance implementation parameters
+ * These recommendations apply to all DAOs and represent best practices
+ */
+
+import { GovernanceImplementationEnum } from "@/shared/types/enums";
+
+/**
+ * Recommended settings for each governance implementation parameter
+ * These are shared across all DAOs as baseline security standards
+ */
+export const RECOMMENDED_SETTINGS: Record<
+ GovernanceImplementationEnum,
+ string
+> = {
+ [GovernanceImplementationEnum.PROPOSAL_FLASHLOAN_PROTECTION]:
+ "The DAO has a protection mechanism that prevents an attacker from using a flash loan to reach the required number of tokens to submit a proposal.",
+
+ [GovernanceImplementationEnum.VOTING_FLASHLOAN_PROTECTION]:
+ "The DAO has a protection mechanism that prevents an attacker from using a flash loan to improve their governance power.",
+
+ [GovernanceImplementationEnum.TIMELOCK_DELAY]:
+ "The Timelock has a waiting period (delay) of at least one day to execute an approved proposal in the DAO.",
+
+ [GovernanceImplementationEnum.VOTING_DELAY]:
+ "The waiting period between the proposal submission and the snapshot of voting power must be at least two days. In addition, the DAO needs to have an activation plan to contact delegates and stakeholders to mobilize their votes in case of an attack.",
+
+ [GovernanceImplementationEnum.PROPOSAL_THRESHOLD]:
+ "The threshold to submit proposals in a DAO needs to be more than 1% of the token's market supply - a sum of governance tokens deposited on centralized exchanges, DEXs and lending markets.",
+
+ [GovernanceImplementationEnum.VETO_STRATEGY]:
+ "A safeguard to veto malicious proposals submitted through on-chain governance must be controlled by the DAO itself to achieve the highest Anticapture security standard.",
+
+ [GovernanceImplementationEnum.PROPOSER_BALANCE_CANCEL]:
+ "Upon submitting a proposal, a governance participant must be required to maintain their voting power above the Proposal Threshold; otherwise, the proposal shall be permissionless to cancel.",
+
+ [GovernanceImplementationEnum.VOTING_PERIOD]:
+ "The period between the start and end of a proposal must be at least seven days.",
+
+ [GovernanceImplementationEnum.VOTE_MUTABILITY]:
+ "The ability to change a vote during the voting period must be provided by the DAO. This mechanism allows voters to withdraw their votes and stop a malicious proposal if the governance interface is compromised.",
+
+ [GovernanceImplementationEnum.VOTING_SUBSIDY]:
+ "Gas fee subsidies for governance voters must be provided to lower the barrier to participation in on-chain proposals.",
+
+ [GovernanceImplementationEnum.SPAM_RESISTANCE]:
+ "Mechanisms should be in place to limit the number of proposals that can be submitted by a single address to prevent governance spam attacks.",
+
+ [GovernanceImplementationEnum.AUDITED_CONTRACTS]:
+ "All governance contracts should be audited by reputable security firms and audit reports should be publicly available.",
+
+ [GovernanceImplementationEnum.INTERFACE_HIJACK]:
+ "The domain should be protected with standard security certificates, made public by its provider. Ideal security here includes a verified front-end, deployed in a immutable manner, linked to an ENS record by the DAO in a domain like vote.DAO.eth and made available through .limo or .link or equivalent.",
+
+ [GovernanceImplementationEnum.ATTACK_PROFITABILITY]:
+ "The cost of acquiring voting power should exceed the potential profit from attacking the treasury. Security councils or veto mechanisms are recommended when treasury value is high.",
+
+ [GovernanceImplementationEnum.SECURITY_COUNCIL]:
+ "A Security Council should be established following best practices (e.g., L2Beat standards) with clear mandate, transparent operations, and regular renewal of authority.",
+
+ [GovernanceImplementationEnum.TIMELOCK_ADMIN]:
+ "The control of the Timelock must be carried out solely by the DAO.",
+};
diff --git a/apps/dashboard/shared/constants/risk-areas.ts b/apps/dashboard/shared/constants/risk-areas.ts
index 3b5f374e1..c5d4ad589 100644
--- a/apps/dashboard/shared/constants/risk-areas.ts
+++ b/apps/dashboard/shared/constants/risk-areas.ts
@@ -14,19 +14,23 @@ import {
export interface RiskAreaConstants {
title: string;
titleAbbreviation: string;
- description: string;
+ description: string | string[];
requirements: GovernanceImplementationEnum[];
}
/**
- * Complete mapping of risk areas with their titles, descriptions and requirements
+ * Complete mapping of defense areas with their titles, abbreviations and requirements
+ * Description field contains general defense definition (what the area protects against)
+ * DAO-specific risk exposures are stored in daoConfig.attackExposure.defenseAreas
*/
export const RISK_AREAS: Record = {
- [RiskAreaEnum.SPAM_VULNERABLE]: {
- title: "Spam Vulnerable",
- titleAbbreviation: "SV",
- description:
- "Means the system can be overwhelmed by fake or low-quality proposals. This clutters governance, wastes resources, and discourages real participation.",
+ [RiskAreaEnum.SPAM_RESISTANCE]: {
+ title: "Spam Resistance",
+ titleAbbreviation: "SR",
+ description: [
+ "Protects the system from being overwhelmed by malicious or low-quality proposals, which can waste resources, discourage meaningful participation, and expose the DAO to a war of attrition.",
+ "This risk typically arises when there are no checks to submit proposals, or when existing safeguards can be bypassed or ignored.",
+ ],
requirements: [
GovernanceImplementationEnum.SPAM_RESISTANCE,
GovernanceImplementationEnum.VOTING_FLASHLOAN_PROTECTION,
@@ -36,18 +40,18 @@ export const RISK_AREAS: Record = {
GovernanceImplementationEnum.VOTING_SUBSIDY,
],
},
- [RiskAreaEnum.ATTACK_PROFITABILITY]: {
- title: "Attack Profitability",
- titleAbbreviation: "AP",
+ [RiskAreaEnum.ECONOMIC_SECURITY]: {
+ title: "Economic Security",
+ titleAbbreviation: "ES",
description:
- "It's the profit someone can take from a system by exploiting its design or timing. In DAOs, this might mean using voting power or insider info for personal gain.",
+ "Ensures the cost of attacking the DAO exceeds potential gains, making governance attacks economically unfeasible.",
requirements: [GovernanceImplementationEnum.ATTACK_PROFITABILITY],
},
[RiskAreaEnum.SAFEGUARDS]: {
title: "Safeguards",
titleAbbreviation: "SG",
description:
- "Protection mechanisms that prevent malicious actions or mistakes from causing harm to the DAO.",
+ "Emergency mechanisms and checks to prevent or cancel malicious proposals before they can be executed.",
requirements: [
GovernanceImplementationEnum.VETO_STRATEGY,
GovernanceImplementationEnum.SECURITY_COUNCIL,
@@ -55,11 +59,11 @@ export const RISK_AREAS: Record = {
GovernanceImplementationEnum.VOTING_SUBSIDY,
],
},
- [RiskAreaEnum.HACKABLE]: {
- title: "Hackable",
- titleAbbreviation: "H",
+ [RiskAreaEnum.CONTRACT_SAFETY]: {
+ title: "Contract Safety",
+ titleAbbreviation: "CS",
description:
- "Vulnerability to exploits that could compromise the DAO's smart contracts or governance processes.",
+ "Ensures governance contracts are secure, audited, and protected from exploits or vulnerabilities.",
requirements: [
GovernanceImplementationEnum.AUDITED_CONTRACTS,
GovernanceImplementationEnum.VOTING_FLASHLOAN_PROTECTION,
@@ -70,18 +74,18 @@ export const RISK_AREAS: Record = {
title: "Response Time",
titleAbbreviation: "RT",
description:
- "How quickly the DAO can react to threats, opportunities, or governance proposals.",
+ "Provides sufficient time windows for the community to detect, react to, and mobilize against malicious proposals.",
requirements: [
GovernanceImplementationEnum.TIMELOCK_DELAY,
GovernanceImplementationEnum.VOTING_DELAY,
GovernanceImplementationEnum.VOTING_PERIOD,
],
},
- [RiskAreaEnum.GOV_FRONTEND_VULNERABILITY]: {
- title: "Gov Front-end Vulnerability",
- titleAbbreviation: "GV",
+ [RiskAreaEnum.GOV_FRONTEND_RESILIENCE]: {
+ title: "Gov Front-end Resilience",
+ titleAbbreviation: "GFR",
description:
- "Weaknesses in the interfaces used for governance participation that could be exploited or lead to governance failures.",
+ "Protects the governance interface from being compromised, hijacked, or manipulated to mislead voters.",
requirements: [
GovernanceImplementationEnum.INTERFACE_HIJACK,
GovernanceImplementationEnum.VOTE_MUTABILITY,
diff --git a/apps/dashboard/shared/dao-config/comp.ts b/apps/dashboard/shared/dao-config/comp.ts
index 757ee881f..5fd3e8ef4 100644
--- a/apps/dashboard/shared/dao-config/comp.ts
+++ b/apps/dashboard/shared/dao-config/comp.ts
@@ -5,6 +5,8 @@ import { CompoundIcon } from "@/shared/components/icons";
import { mainnet } from "viem/chains";
import { QUORUM_CALCULATION_TYPES } from "@/shared/constants/labels";
import { MainnetIcon } from "@/shared/components/icons/MainnetIcon";
+import { RECOMMENDED_SETTINGS } from "@/shared/constants/recommended-settings";
+import { RiskAreaEnum } from "@/shared/types/enums/RiskArea";
export const COMP: DaoConfiguration = {
name: "Compound",
@@ -48,77 +50,93 @@ export const COMP: DaoConfiguration = {
// Fields are sorted alphabetically by GovernanceImplementationEnum for readability
fields: {
[GovernanceImplementationEnum.AUDITED_CONTRACTS]: {
- value: "Yes",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.AUDITED_CONTRACTS
].description,
- riskExplanation: "Compound contracts are audited.", //Link: https://www.openzeppelin.com/news/compound-governor-bravo-audit
+ currentSetting:
+ "Compound contracts have been audited, and the audit is publicly available.",
+ impact:
+ "With its governance contracts audited, the risk of vulnerabilities in them is minimized.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.AUDITED_CONTRACTS],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.INTERFACE_HIJACK]: {
- value: "No",
riskLevel: RiskLevel.HIGH,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.INTERFACE_HIJACK
].description,
+ currentSetting:
+ "The domain is not signed with a valid signature (DNSSEC) and it is not possible to establish a secure connection to it (HTTPS).",
+ impact:
+ "Without protection for its governance domains and interfaces, governance participants may be manipulated into voting for an outcome that harms the DAO.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.INTERFACE_HIJACK],
+ nextStep:
+ "Nouns needs to enable DNSSEC and HTTPS on the domains of its governance interfaces, in order to raise its standard to Medium Risk.",
requirements: [
"Without the proper protections(DNSSEC/SPF/DKIM/DMARC), attackers can spoof governance UIs by hijacking unprotected domains.", // https://internet.nl/site/www.tally.xyz/3493806/
],
- riskExplanation:
- "The domain is not signed with a valid signature (DNSSEC) and it is not possible to establish a secure connection to it (HTTPS).",
},
[GovernanceImplementationEnum.ATTACK_PROFITABILITY]: {
- value: "U$2.72B",
riskLevel: RiskLevel.HIGH,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.ATTACK_PROFITABILITY
].description,
+ currentSetting:
+ "If Compound gets captured, the entire TVL of the protocol could be stolen — including users' funds.",
+ impact: "$2.7B could be stolen from Compound, including user funds.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[
+ GovernanceImplementationEnum.ATTACK_PROFITABILITY
+ ],
+ nextStep:
+ "Reduce the capital at risk controlled by the DAO (Comets), or increase the Delegated Cap and Average Turnout of Compound governance.",
requirements: [
"An attack on Compound doesn’t just put its treasury at risk — it also endangers users’ funds. The Governor can authorize a malicious address to move money across all its markets, whether in v2 or v3.",
"To reduce the profitability of an attack, Compound needs to remove that permission from the Governor.",
],
- riskExplanation:
- "If Compound gets captured, the entire TVL of the protocol could be stolen — including users’ funds.",
},
[GovernanceImplementationEnum.PROPOSAL_FLASHLOAN_PROTECTION]: {
- value: "Yes",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.PROPOSAL_FLASHLOAN_PROTECTION
].description,
- riskExplanation:
- "Voting power are based on block previous to when voters could first cast a vote, making flashloan votes impossible.",
+ currentSetting:
+ "It protects the DAO from a flash loan aimed at reaching the Proposal Threshold and submitting a proposal, by taking a snapshot of the governance power from delegates/holders one block before the proposal submission.",
+ impact:
+ "It is not possible to use a flash loan to reach the amount required to submit a proposal.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[
+ GovernanceImplementationEnum.PROPOSAL_FLASHLOAN_PROTECTION
+ ],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.PROPOSAL_THRESHOLD]: {
- value: "25K $COMP",
riskLevel: RiskLevel.MEDIUM,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.PROPOSAL_THRESHOLD
].description,
+ currentSetting:
+ "The proposal threshold is 0,9% of the market supply, which is considered medium risk.",
+ impact:
+ "$COMP has higher liquidity, making it easier for a large attacker to reach the Proposal Threshold and submit a proposal.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.PROPOSAL_THRESHOLD],
+ nextStep:
+ "The Proposal Threshold should be at least 0.5% of the governance token's market supply.",
requirements: [
"The proposal threshold should be increased based on the amount of $COMP market supply.",
],
- riskExplanation:
- "The proposal threshold is 0,9% of the market supply, which is considered medium risk.",
- },
- [GovernanceImplementationEnum.PROPOSAL_THRESHOLD_CANCEL]: {
- value: "Yes",
- riskLevel: RiskLevel.HIGH,
- description:
- GOVERNANCE_IMPLEMENTATION_CONSTANTS[
- GovernanceImplementationEnum.PROPOSAL_THRESHOLD_CANCEL
- ].description,
- riskExplanation:
- "If the proposer maintains governance power above the Proposal Threshold during the Voting Period, the proposal will be canceled",
},
[GovernanceImplementationEnum.SECURITY_COUNCIL]: {
- value: "Yes",
riskLevel: RiskLevel.MEDIUM,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
@@ -127,112 +145,182 @@ export const COMP: DaoConfiguration = {
requirements: [
"The Compound Security Council needs to raise the threshold to 75% for approvals on their multisig to be considered Low Risk.",
],
- riskExplanation:
+ currentSetting:
"Compound has the Proposal Guardian, a multisig responsible for canceling malicious proposals.",
+ impact:
+ "The Security Council can protect the DAO from malicious proposals by canceling them after the 4/8 multisig approval.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.SECURITY_COUNCIL],
+ nextStep:
+ "Follow L2Beat's standards to have a more secure Security Council.",
},
[GovernanceImplementationEnum.SPAM_RESISTANCE]: {
- value: "No",
riskLevel: RiskLevel.HIGH,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.SPAM_RESISTANCE
].description,
+ currentSetting: "Compound governance is vulnerable to spam.",
+ impact:
+ "A single address can submit multiple proposals, potentially masking an attack within one of them.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.SPAM_RESISTANCE],
+ nextStep:
+ "It is necessary to limit the number of proposals that can be submitted by a single address.",
requirements: [
"Compound has no limit on active proposals or proposals submitted per address.",
],
- riskExplanation: "Compound governance is vulnerable to spam.",
},
[GovernanceImplementationEnum.TIMELOCK_ADMIN]: {
- value: "Yes",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.TIMELOCK_ADMIN
].description,
- riskExplanation: "Governor has Admin role on timelock.",
+ currentSetting: "Timelock is controlled by the Governor.",
+ impact:
+ "Since the Governor is the administrator of the Timelock, only the DAO can control it - decentralizing its governance.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.TIMELOCK_ADMIN],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.TIMELOCK_DELAY]: {
- value: "2 days",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.TIMELOCK_DELAY
].description,
- riskExplanation: "2 days is a sufficient delay for Timelock.",
+ currentSetting: "The Voting Period is set to 2 days",
+ impact:
+ "There is a protected delay between proposal approval and execution.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.TIMELOCK_DELAY],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.VETO_STRATEGY]: {
- value: "Yes",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VETO_STRATEGY
].description,
- riskExplanation:
+ currentSetting:
"There is a veto strategy controlled by the Compound DAO.",
+ impact:
+ "Compound can veto malicious proposals with the Security Council",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VETO_STRATEGY],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.VOTE_MUTABILITY]: {
- value: "No",
riskLevel: RiskLevel.MEDIUM,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VOTE_MUTABILITY
].description,
+ currentSetting:
+ "The DAO does not allow changing votes once they have been cast.",
+ impact:
+ "Governance participants cannot change their votes after casting them. In the event of a governance interface hijack, they may be manipulated into voting for the opposite of their intended choice, enabling an attack on the DAO.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VOTE_MUTABILITY],
+ nextStep:
+ "Allow voters to change their vote until the Voting Period ends.",
requirements: [
"It is necessary to allow voters to change their votes until the end of the proposal to prevent them from being misled in an attack on Compound's governance DNS.",
],
- riskExplanation:
- "The lack of vote mutability jeopardizes DAO decisions if its main voting interface is attacked.",
},
[GovernanceImplementationEnum.VOTING_DELAY]: {
- value: "1 day and 19 hours",
riskLevel: RiskLevel.HIGH,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VOTING_DELAY
].description,
+ currentSetting: "The Voting Period is set to 1 day and 19 hours",
+ impact:
+ "The Voting Delay period can be longer. This gives delegates and stakeholders little time to coordinate their votes and for the DAO to protect itself against an attack. This poses a governance risk.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VOTING_DELAY],
+ nextStep: "The Voting Delay should be at least two days.",
requirements: [
"The Voting Delay needs to be more than 2 days for be considered as Medium Risk.",
],
- riskExplanation:
- "With the current Voting Delay, Compound has little time left to gather votes to protect its governance, in case of an attack.",
},
[GovernanceImplementationEnum.VOTING_FLASHLOAN_PROTECTION]: {
- value: "Yes",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VOTING_FLASHLOAN_PROTECTION
].description,
- riskExplanation:
- "Voting power are based on block previous to when voters could first cast a vote, making flashloan votes impossible.",
+ currentSetting:
+ "It protects the DAO from a flash loan aimed to increase their voting power, by taking a snapshot of the governance power from delegates/holders one block before the Voting Period starts",
+ impact:
+ "It is not possible to use a flash loan to increase voting power and approve a proposal.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[
+ GovernanceImplementationEnum.VOTING_FLASHLOAN_PROTECTION
+ ],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.VOTING_PERIOD]: {
- value: "2 days and 17 hours",
riskLevel: RiskLevel.HIGH,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VOTING_PERIOD
].description,
+ currentSetting: "The Voting Period is set to 2 days and 17 hours",
+ impact:
+ "The Voting Period can be longer. A short voting period makes it harder for stakeholders to coordinate and vote against a malicious proposal submitted to the DAO.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VOTING_PERIOD],
+ nextStep: "The Voting Period should be at least two days.",
requirements: [
"The Voting Period must have, at least, 3 days to be classified as Medium Risk.",
],
- riskExplanation:
- "Compound has a short timeframe to prepare itself in case of a governance attack.",
},
[GovernanceImplementationEnum.VOTING_SUBSIDY]: {
- value: "Yes",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VOTING_SUBSIDY
].description,
- riskExplanation:
- "The voting subsidy exists in the Governor code, and is already implemented to voters.", // https://app.compound.finance/extensions/comp_vote
+ currentSetting:
+ "Voting subsidy exists in the Governor code, and is already implemented to voters.",
+ impact:
+ "By subsidizing governance participants' voting costs, there is greater participation and stronger incentives for delegates to protect the DAO, since they do not incur gas fees to vote.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VOTING_SUBSIDY],
+ nextStep: "The parameter is in its lowest-risk condition.",
+ },
+ },
+ },
+ attackExposure: {
+ defenseAreas: {
+ [RiskAreaEnum.SPAM_RESISTANCE]: {
+ description:
+ "A moderate proposal threshold combined with governance vulnerability to spam reduces the cost of flooding the system, while a short 2-day and 17-hour voting period limits reaction time, resulting in high exposure to governance spam.",
+ },
+ [RiskAreaEnum.ECONOMIC_SECURITY]: {
+ description:
+ "If Compound governance is captured, the protocol’s entire TVL — including users’ deposited funds — could be at risk. The high potential financial upside makes governance attacks economically attractive.",
+ },
+ [RiskAreaEnum.SAFEGUARDS]: {
+ description:
+ "A Proposal Guardian multisig exists and can cancel malicious proposals, providing a layer of protection. However, this safeguard is limited in scope and introduces moderate centralization risk.",
+ },
+ [RiskAreaEnum.CONTRACT_SAFETY]: {
+ description: "All metrics in this defense are currently in low risk.",
+ },
+ [RiskAreaEnum.RESPONSE_TIME]: {
+ description:
+ "A 1-day and 19-hour voting delay combined with a 2-day and 17-hour voting period limits the time available for coordination and defensive action, increasing the risk of rushed or insufficiently defended governance decisions.",
+ },
+ [RiskAreaEnum.GOV_FRONTEND_RESILIENCE]: {
+ description:
+ "Interface protections are absent or not properly hardened, and immutable votes limit recovery in the event of front-end compromise, resulting in high governance interface risk.",
},
},
},
resilienceStages: true,
tokenDistribution: true,
- riskAnalysis: true,
dataTables: true,
};
diff --git a/apps/dashboard/shared/dao-config/ens.ts b/apps/dashboard/shared/dao-config/ens.ts
index fd7ded06b..4ea0e9003 100644
--- a/apps/dashboard/shared/dao-config/ens.ts
+++ b/apps/dashboard/shared/dao-config/ens.ts
@@ -1,7 +1,12 @@
import { DaoConfiguration } from "@/shared/dao-config/types";
-import { RiskLevel, GovernanceImplementationEnum } from "@/shared/types/enums";
+import {
+ RiskLevel,
+ GovernanceImplementationEnum,
+ RiskAreaEnum,
+} from "@/shared/types/enums";
import { calculateMonthsBefore } from "@/shared/utils";
import { GOVERNANCE_IMPLEMENTATION_CONSTANTS } from "@/shared/constants/governance-implementations";
+import { RECOMMENDED_SETTINGS } from "@/shared/constants/recommended-settings";
import { EnsIcon } from "@/shared/components/icons";
import { mainnet } from "viem/chains";
import { QUORUM_CALCULATION_TYPES } from "@/shared/constants/labels";
@@ -62,187 +67,293 @@ export const ENS: DaoConfiguration = {
riskLevel: RiskLevel.HIGH,
supportsLiquidTreasuryCall: true,
},
- riskAnalysis: true,
governanceImplementation: {
// Fields are sorted alphabetically by GovernanceImplementationEnum for readability
fields: {
[GovernanceImplementationEnum.AUDITED_CONTRACTS]: {
- value: "Yes",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.AUDITED_CONTRACTS
].description,
+ currentSetting:
+ "The ENS DAO contracts have been audited, and the audit is publicly available.",
+ impact:
+ "With its governance contracts audited, the risk of vulnerabilities in them is minimized.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.AUDITED_CONTRACTS],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.INTERFACE_HIJACK]: {
- value: "No",
riskLevel: RiskLevel.MEDIUM,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.INTERFACE_HIJACK
].description,
- requirements: [
- "For maximum security, the DAO should have its frontend reviewed by the DAO or audit and then made verifiably immutable",
- "A solution could look like a frontend made available on IPFS through eth.limo, with their code hashed and put on chain by the DAO, then verified for subresource integrity",
- "The governance interface used (Tally) has the standard protections to prevent external tampering with the frontend accessed",
- "The platform is still exposed to any malicious or compromised actors inside the interface provider team",
- ],
- riskExplanation: `Although protected from spoofing or hijacking, the service used for voting could still be internally compromised.\n
- A change in the voting interface could be used to manipulate the results of the vote, hiding malicious txns, or even changing selection of votes.`,
+ currentSetting:
+ "The ENS governance interface has a secure HTTPS connection and is signed with DNSSEC.",
+ impact:
+ "The governance interface domain shows the basic security certificates, but without immutable decentralized storage it is not censorship-resistant or verifiable.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.INTERFACE_HIJACK],
+ nextStep:
+ "The ENS governance interface domain should be hosted on IPFS.",
},
[GovernanceImplementationEnum.ATTACK_PROFITABILITY]: {
- value: "~100M USD",
riskLevel: RiskLevel.MEDIUM,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.ATTACK_PROFITABILITY
].description,
- requirements: [
- "Once a proposal snapshot block has passed, if any single address or group has over 50% of the delegated supply, they can approve the proposal without the need of of any other support.",
- "Currently, the active supply in ENS DAO - meaning the voting power of delegates who have voted in recent proposals - is a little below 20% of the delegated supply.",
- "Even without 50% of the delegated supply, an address with over 50% of the active supply could present a big risk to the DAO if not for the Security Council, active until July 2026.",
- "The DAO should dedicate effort to the increase of governance participation, aiming at an active supply worth at least double the amount of liquid assets under governance management.",
- ],
+ currentSetting:
+ "Because ENS has a large liquid treasury (over $100M), attacking the DAO would be highly profitable. In this case, the Veto Strategy/Security Council is necessary.",
+ impact:
+ "An attacker has fewer incentives to capture the DAO given the difference between liquid assets and treasury size, and attacker has financial incentives to takeover governance power.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[
+ GovernanceImplementationEnum.ATTACK_PROFITABILITY
+ ],
+ nextStep:
+ "The Delegated Cap should increase, incentivizing delegation to ENS delegates. This raises the cost of attacking the DAO and reduces the potential profitability of an attack.",
},
[GovernanceImplementationEnum.PROPOSAL_FLASHLOAN_PROTECTION]: {
- value: "Yes",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.PROPOSAL_FLASHLOAN_PROTECTION
].description,
+ currentSetting:
+ "It protects the DAO from a flash loan aimed at reaching the Proposal Threshold and submitting a proposal, by taking a snapshot of the governance power from delegates/holders one block before the proposal submission.",
+ impact:
+ "It is not possible to use a flash loan to reach the amount required to submit a proposal.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[
+ GovernanceImplementationEnum.PROPOSAL_FLASHLOAN_PROTECTION
+ ],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.PROPOSAL_THRESHOLD]: {
- value: "100k ENS",
riskLevel: RiskLevel.MEDIUM,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.PROPOSAL_THRESHOLD
].description,
+ currentSetting:
+ "The Proposal Threshold is set to 100K $ENS (0,1% Total Supply)",
+ impact:
+ "ENS has a proposal threshold that makes it harder for attackers to be able to create proposals without reaching a significant level of accumulation first.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.PROPOSAL_THRESHOLD],
+ nextStep:
+ "The Proposal Threshold can be increased to a value above 1% market supply, in order to raise the cost of submitting proposals in governance and reduce the likelihood of spam.",
requirements: [
"A low proposal threshold lets attackers or small coalitions submit governance actions too easily, forcing the DAO to vote on spam or malicious items.",
"The DAO should set the proposal threshold at ≥ 1 % of circulating market supply (CEX + DEX + lending pools) so that only wallets with meaningful economic stake can create proposals.",
],
},
- [GovernanceImplementationEnum.PROPOSAL_THRESHOLD_CANCEL]: {
- value: "No",
- riskLevel: RiskLevel.HIGH,
- description:
- GOVERNANCE_IMPLEMENTATION_CONSTANTS[
- GovernanceImplementationEnum.PROPOSAL_THRESHOLD_CANCEL
- ].description,
- requirements: [
- "Once a proposal is submitted, the proposer can immediately dump their tokens, reducing their financial risk in case of an attack.",
- "The DAO must enforce a permissionless way to cancel any live proposal if the proposer's voting power drops below the proposal-creation threshold.",
- ],
- },
[GovernanceImplementationEnum.PROPOSER_BALANCE_CANCEL]: {
- value: "No",
riskLevel: RiskLevel.HIGH,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.PROPOSER_BALANCE_CANCEL
].description,
+ currentSetting:
+ "There is no ability to cancel a proposal if the proposer's balance falls below the Proposal Threshold after submitting it.",
+ impact:
+ "An attacker can buy tokens to submit a proposal in the DAO, vote with them, and sell them during the voting period. There is nothing in ENS governance that protects against this or prevents the attacker from doing so.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[
+ GovernanceImplementationEnum.PROPOSER_BALANCE_CANCEL
+ ],
+ nextStep:
+ "The governance contract should cancel a proposal if the address that submitted it has a governance token balance below the Proposal Threshold.",
requirements: [
"Once a proposal is submitted, the proposer can immediately dump their tokens, reducing their financial risk in case of an attack.",
"The DAO must enforce a permissionless way to cancel any live proposal if the proposer's voting power drops below the proposal-creation threshold.",
],
},
[GovernanceImplementationEnum.SECURITY_COUNCIL]: {
- value: "Yes",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.SECURITY_COUNCIL
].description,
+ currentSetting:
+ "ENS has a Security Council, managed by a 4/8 multisig, whose authority to cancel proposals must be renewed every two years (and will expire in July 2026).",
+ impact: "ENS can veto malicious proposals with the Security Council",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.SECURITY_COUNCIL],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.SPAM_RESISTANCE]: {
- value: "No",
riskLevel: RiskLevel.HIGH,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.SPAM_RESISTANCE
].description,
+ currentSetting:
+ "There is no limit to the number of proposals that a single address can submit in the DAO.",
+ impact:
+ "A single address can submit multiple proposals, potentially masking an attack within one of them or make multiple malicious proposals.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.SPAM_RESISTANCE],
+ nextStep:
+ "It is necessary to limit the number of proposals that can be submitted by a single address.",
requirements: [
"An attacker can swamp the system with simultaneous proposals, overwhelming voters to approve an attack through a war of attrition",
"The DAO should impose—and automatically enforce—a hard cap on the number of active proposals any single address can have at once.",
],
},
[GovernanceImplementationEnum.TIMELOCK_ADMIN]: {
- value: "No",
riskLevel: RiskLevel.MEDIUM,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.TIMELOCK_ADMIN
].description,
+ currentSetting: "Governor is the only Admin role on timelock.",
+ impact:
+ "Since the Governor is the only administrator of the Timelock, only the DAO can control it - decentralizing its governance.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.TIMELOCK_ADMIN],
+ nextStep: "The parameter is in its lowest-risk condition.",
requirements: [
"The timelock admin can control execution, canceling, upgrades or critical parameter changes; if this power sits outside audited, DAO-approved contracts, attackers or insiders can sidestep on-chain voting.",
"Admin rights should rest only with DAO governance plus contracts it explicitly approves after a public audit.",
],
},
[GovernanceImplementationEnum.TIMELOCK_DELAY]: {
- value: "2 days",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.TIMELOCK_DELAY
].description,
+ currentSetting:
+ "The Timelock execution delay for an approved proposal is 2 days.",
+ impact:
+ "There is a protected delay between proposal approval and execution.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.TIMELOCK_DELAY],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.VETO_STRATEGY]: {
- value: "Yes",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VETO_STRATEGY
].description,
+ currentSetting:
+ "ENS has a Security Council that is able to veto malicious proposals.",
+ impact: "ENS can veto malicious proposals with the Security Council",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VETO_STRATEGY],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.VOTE_MUTABILITY]: {
- value: "No",
riskLevel: RiskLevel.MEDIUM,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VOTE_MUTABILITY
].description,
+ currentSetting:
+ "The DAO does not allow changing votes once they have been cast.",
+ impact:
+ "Governance participants cannot change their votes after casting them. In the event of an interface hijack on the voting platform to support the attack, voters cannot revert their vote.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VOTE_MUTABILITY],
+ nextStep:
+ "Allow voters to change their vote until the Voting Period ends.",
requirements: [
"If voters cannot revise their ballots, a last-minute interface exploit or late discovery of malicious code can trap delegates in a choice that now favors an attacker, weakening the DAO’s defense.",
"The governance contract should let any voter overwrite their previous vote while the voting window is open—ideally through a single castVoteWithReasonAndParams call or equivalent.",
],
},
[GovernanceImplementationEnum.VOTING_DELAY]: {
- value: "12 seconds",
riskLevel: RiskLevel.HIGH,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VOTING_DELAY
].description,
+ currentSetting: "The Voting Delay is set to 12 seconds.",
+ impact:
+ "The Voting Delay period is extremely short. This gives delegates and stakeholders little time to coordinate their votes and for the DAO to protect itself against an attack. This poses a governance risk.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VOTING_DELAY],
+ nextStep:
+ "The Voting Delay needs to be increased to at least 2 days in order to be considered Medium Risk.",
requirements: [
"Voting delay is the time between proposal submission and the snapshot that fixes voting power. The current one-block delay lets attackers rush proposals before token-holders or delegates can react.",
"The DAO should enforce a delay of at least two full days and have an automatic alert plan that notifies major voters the moment a proposal is posted.",
],
},
[GovernanceImplementationEnum.VOTING_FLASHLOAN_PROTECTION]: {
- value: "Yes(default)",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VOTING_FLASHLOAN_PROTECTION
].description,
+ currentSetting:
+ "It protects the DAO from a flash loan aimed to increase their voting power, by taking a snapshot of the governance power from delegates/holders one block before the Voting Period sarts",
+ impact:
+ "It is not possible to use a flash loan to increase voting power and approve a proposal.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[
+ GovernanceImplementationEnum.VOTING_FLASHLOAN_PROTECTION
+ ],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.VOTING_PERIOD]: {
- value: "7 days",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VOTING_PERIOD
].description,
+ currentSetting: "The Voting Period is set to 5d 14h 24min.",
+ impact:
+ "The current Voting Period is sufficient for governance participants to cast their votes.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VOTING_PERIOD],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.VOTING_SUBSIDY]: {
- value: "Yes",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VOTING_SUBSIDY
].description,
+ currentSetting:
+ "There is a subsidy to help voters participate in governance voting.",
+ impact:
+ "By subsidizing governance participants' voting costs, there is greater participation and stronger incentives for delegates to protect the DAO, since they do not incur gas fees to vote.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VOTING_SUBSIDY],
+ nextStep: "The parameter is in its lowest-risk condition.",
+ },
+ },
+ },
+ attackExposure: {
+ defenseAreas: {
+ [RiskAreaEnum.SPAM_RESISTANCE]: {
+ description:
+ "Proposal threshold is below the ideal level and proposal submissions are unrestricted, significantly reducing resistance to sustained proposal spam.",
+ },
+ [RiskAreaEnum.ECONOMIC_SECURITY]: {
+ description:
+ "A large treasury held in non-native assets increases attack profitability, requiring additional veto or council mechanisms to keep economic risk at moderate levels.",
+ },
+ [RiskAreaEnum.SAFEGUARDS]: {
+ description:
+ "Proposals cannot be cancelled when the proposer's balance drops below the threshold, enabling spam, governance distraction, and low-cost attack experimentation.",
+ },
+ [RiskAreaEnum.CONTRACT_SAFETY]: {
+ description: "All metrics in this defense are currently in low risk.",
+ },
+ [RiskAreaEnum.RESPONSE_TIME]: {
+ description:
+ "An extremely short voting delay leaves little time for review or coordination, increasing the risk of rushed or unchallenged governance decisions.",
+ },
+ [RiskAreaEnum.GOV_FRONTEND_RESILIENCE]: {
+ description:
+ "Interface protections are present but not fully hardened, and immutable votes limit recovery from front-end compromise, resulting in moderate governance interface risk.",
},
},
},
diff --git a/apps/dashboard/shared/dao-config/gtc.ts b/apps/dashboard/shared/dao-config/gtc.ts
index cc371ea97..0cd53191f 100644
--- a/apps/dashboard/shared/dao-config/gtc.ts
+++ b/apps/dashboard/shared/dao-config/gtc.ts
@@ -5,6 +5,8 @@ import { GitcoinIcon } from "@/shared/components/icons";
import { mainnet } from "viem/chains";
import { QUORUM_CALCULATION_TYPES } from "@/shared/constants/labels";
import { MainnetIcon } from "@/shared/components/icons/MainnetIcon";
+import { RECOMMENDED_SETTINGS } from "@/shared/constants/recommended-settings";
+import { RiskAreaEnum } from "@/shared/types/enums/RiskArea";
export const GTC: DaoConfiguration = {
name: "Gitcoin",
@@ -43,203 +45,285 @@ export const GTC: DaoConfiguration = {
attackProfitability: {
riskLevel: RiskLevel.HIGH,
},
- riskAnalysis: true,
governanceImplementation: {
// Fields are sorted alphabetically by GovernanceImplementationEnum for readability
fields: {
[GovernanceImplementationEnum.AUDITED_CONTRACTS]: {
- value: "Yes",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.AUDITED_CONTRACTS
].description,
- riskExplanation:
- "The contracts have been audited for smart contract security.",
+ currentSetting:
+ "The Gitcoin DAO contracts have been audited, and the audit is publicly available.",
+ impact:
+ "With its governance contracts audited, the risk of vulnerabilities in them is minimized.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.AUDITED_CONTRACTS],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.INTERFACE_HIJACK]: {
- value: "No",
riskLevel: RiskLevel.MEDIUM,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.INTERFACE_HIJACK
].description,
+ currentSetting:
+ "The governance interfaces and domain of the Optimism DAO do not have DNS protection, leaving voters vulnerable to spoofing and hijacking attacks.",
+ impact:
+ "Without protection for its governance domains and interfaces, governance participants may be manipulated into voting for an outcome that harms the DAO.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.INTERFACE_HIJACK],
+ nextStep:
+ "Gitcoin needs to enable DNSSEC and HTTPS on the domains of its governance interfaces, in order to raise its standard to Medium Risk.",
requirements: [
"Without the proper protections(DNSSEC/SPF/DKIM/DMARC), attackers can spoof governance UIs by hijacking unprotected domains.",
"Currently, the DAO’s domains have no publicly verifiable DNS-level protections (High Risk).",
"Secure every DAO‑owned domain with Industry standard and publish a security‑contact record.",
],
- riskExplanation:
- "The DAO's domains have no publicly verifiable DNS-level protections we are aware of.",
},
[GovernanceImplementationEnum.ATTACK_PROFITABILITY]: {
- value: "~$500k",
riskLevel: RiskLevel.HIGH,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.ATTACK_PROFITABILITY
].description,
+ currentSetting:
+ "The value of the DAO's liquid treasury is greater than the total value of the delegated tokens, which represents a risk for the DAO.",
+ impact:
+ "With a low delegated cap, the cost to carry out an attack is lower and the attack's profitability is higher.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[
+ GovernanceImplementationEnum.ATTACK_PROFITABILITY
+ ],
+ nextStep:
+ "The Delegated Cap should increase, incentivizing delegation to ENS delegates. This raises the cost of attacking the DAO and reduces the potential profitability of an attack.",
requirements: [
"Increase the delegation supply and active voter set to lower the profitability of an attacker.",
"Get the delegated supply above the value directly available for proposal execution.",
],
- riskExplanation:
- "The liquid treasury of the DAO is ~$500k bigger than its current delegated supply.",
},
[GovernanceImplementationEnum.PROPOSAL_FLASHLOAN_PROTECTION]: {
- value: "Yes",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.PROPOSAL_FLASHLOAN_PROTECTION
].description,
- riskExplanation:
- "The DAO is not vulnerable to proposal flashloan attacks.",
+ currentSetting:
+ "It protects the DAO from a flash loan aimed at reaching the Proposal Threshold and submitting a proposal, by taking a snapshot of the governance power from delegates/holders one block before the proposal submission.",
+ impact:
+ "It is not possible to use a flash loan to reach the amount required to submit a proposal.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[
+ GovernanceImplementationEnum.PROPOSAL_FLASHLOAN_PROTECTION
+ ],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.PROPOSAL_THRESHOLD]: {
- value: "150k GTC",
riskLevel: RiskLevel.HIGH,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.PROPOSAL_THRESHOLD
].description,
- riskExplanation:
- "The proposal threshold is 150k GTC, which is the minimum amount of GTC required to propose a new proposal. The level of risk of this depends on the liquidity on markets.",
- },
- [GovernanceImplementationEnum.PROPOSAL_THRESHOLD_CANCEL]: {
- value: "No",
- riskLevel: RiskLevel.HIGH,
- description:
- GOVERNANCE_IMPLEMENTATION_CONSTANTS[
- GovernanceImplementationEnum.PROPOSAL_THRESHOLD_CANCEL
- ].description,
- requirements: [
- "Stablish a defense system that allows the DAO to cancel proposals if the original proposer doesn't have the required amount of GTC to meet threshold any longer.",
- ],
- riskExplanation:
- "Currently an attacker can propose by holding enough tokens, dump them on the market and the proposal would stay valid.",
+ currentSetting:
+ "The Proposal Threshold is set to 150K $GTC (0,5% Total Supply)",
+ impact:
+ "With the current Proposal Threshold, the cost of submitting a proposal to the DAO makes spam attacks more difficult for attackers.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.PROPOSAL_THRESHOLD],
+ nextStep: "To be defined",
},
[GovernanceImplementationEnum.SECURITY_COUNCIL]: {
- value: "No",
riskLevel: RiskLevel.NONE,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.SECURITY_COUNCIL
].description,
- riskExplanation: "The DAO has no security council.",
+ currentSetting: "Gitcoin does not have a Security Council.",
+ impact:
+ "The DAO doesn't have a veto strategy or Security Council. In this case, the only way to protect from malicious proposals is through mass defense at the voting stage.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.SECURITY_COUNCIL],
+ nextStep: "A Security Council should be created as a Veto Strategy.",
},
[GovernanceImplementationEnum.SPAM_RESISTANCE]: {
- value: "No",
riskLevel: RiskLevel.HIGH,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.SPAM_RESISTANCE
].description,
+ currentSetting:
+ "There is no limit to the number of proposals that a single address can submit in the DAO.",
+ impact:
+ "A single address can submit multiple proposals, potentially masking an attack within one of them.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.SPAM_RESISTANCE],
+ nextStep:
+ "It is necessary to limit the number of proposals that can be submitted by a single address.",
requirements: [
"The DAO should establish a system to stop proposers from having multiple proposals at the same time.",
],
- riskExplanation:
- "Currently, an attacker can submit multiple proposals and cause a war of attrition against defending delegates.",
},
[GovernanceImplementationEnum.TIMELOCK_ADMIN]: {
- value: "No",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.TIMELOCK_ADMIN
].description,
- riskExplanation:
- "There's no external entity with control to the timelock roles.",
+ currentSetting: "Governor has Admin role on timelock",
+ impact:
+ "Since the Governor is the administrator of the Timelock, only the DAO can control it - decentralizing its governance.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.TIMELOCK_ADMIN],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.TIMELOCK_DELAY]: {
- value: "2 days",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.TIMELOCK_DELAY
].description,
- riskExplanation:
- "The timelock delay of two days gives time for the DAO to respond before execution.",
+ currentSetting:
+ "The Timelock execution delay for an approved proposal is 2 days.",
+ impact:
+ "There is a protected delay between proposal approval and execution.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.TIMELOCK_DELAY],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.VETO_STRATEGY]: {
- value: "No",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VETO_STRATEGY
].description,
- riskExplanation: "The DAO has no veto strategy.",
+ currentSetting: "The DAO has not Veto Strategy",
+ impact: "There is no protection mechanism to veto malicious proposals.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VETO_STRATEGY],
+ nextStep:
+ "The DAO needs to establish a mechanism capable of vetoing malicious proposals.",
},
[GovernanceImplementationEnum.VOTE_MUTABILITY]: {
- value: "No",
riskLevel: RiskLevel.MEDIUM,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VOTE_MUTABILITY
].description,
+ currentSetting:
+ "The DAO does not allow changing votes once they have been cast.",
+ impact:
+ "Governance participants cannot change their votes after casting them. In the event of a governance interface hijack, they may be manipulated into voting for the opposite of their intended choice, enabling an attack on the DAO.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VOTE_MUTABILITY],
+ nextStep:
+ "Allow voters to change their vote until the Voting Period ends.",
requirements: [
"If voters cannot revise their ballots, a last-minute interface exploit or late discovery of malicious code can trap delegates in a choice that now favors an attacker, weakening the DAO’s defense.",
"The governance contract should let any voter overwrite their previous vote while the voting window is open—ideally through an adapted castVoteWithReasonAndParams call or equivalent.",
],
- riskExplanation:
- "In case of an exploit that affects the voting platforms, immutable votes can leave delegates stuck with a incorrect vote made in a compromised interface.",
},
[GovernanceImplementationEnum.VOTING_DELAY]: {
- value: "44 hours",
riskLevel: RiskLevel.MEDIUM,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VOTING_DELAY
].description,
+ currentSetting: "The Voting Delay is set to 1 day and 19 hours",
+ impact:
+ "Given the current Voting Delay, the DAO has sufficient time to coordinate stakeholders and wallets before the snapshot (that counts votes) occurs.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VOTING_DELAY],
+ nextStep: "The parameter is in its lowest-risk condition.",
requirements: [
"Voting delay is the time between proposal submission and the snapshot that fixes voting power. The current 44 hours delay is the time to redelegate and activate delegates before voting starts.",
"Our standard for low risk is of at least 2 days, to give time for a coordinated response with holders that need to redelegate in case of an attacker",
],
- riskExplanation:
- "With less than 2 days of voting delay, token holders might miss the chance to delegate in support of the DAOs defense",
},
[GovernanceImplementationEnum.VOTING_FLASHLOAN_PROTECTION]: {
- value: "Yes",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VOTING_FLASHLOAN_PROTECTION
].description,
- riskExplanation:
- "Delegates voting power are based on its delegation on block previous to when they could first cast a vote, making flashloan votes impossible.",
+ currentSetting:
+ "It protects the DAO from a flash loan aimed to increase their voting power, by taking a snapshot of the governance power from delegates/holders one block before the Voting Period sarts",
+ impact:
+ "It is not possible to use a flash loan to increase voting power and approve a proposal.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[
+ GovernanceImplementationEnum.VOTING_FLASHLOAN_PROTECTION
+ ],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.VOTING_PERIOD]: {
- value: "5 days and 14 hours",
riskLevel: RiskLevel.MEDIUM,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VOTING_PERIOD
].description,
+ currentSetting: "The Voting Period is set to 5 days and 14 hours.",
+ impact:
+ "The current Voting Period is sufficient for governance participants to cast their votes.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VOTING_PERIOD],
+ nextStep:
+ "The Voting Period should be equal to or greater than 7 days.",
requirements: [
"The voting period is 5 days and 14 hours, with the recommended safety being of 7 or more for a low level of risk.",
"Increase the voting period to allow for more delegates to participate in the voting process. and increase attack costs.",
],
- riskExplanation:
- "The voting period is 5 days and 14 hours, with the recommended safety being of 7 or more for a low level of risk.",
},
[GovernanceImplementationEnum.VOTING_SUBSIDY]: {
- value: "No",
riskLevel: RiskLevel.HIGH,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VOTING_SUBSIDY
].description,
+ currentSetting:
+ "There is no subsidy to help voters participate in governance voting.",
+ impact:
+ "Without subsidies, voters incur costs to participate in governance. During periods of high gas fees, participation may decrease, making the DAO easier to attack.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VOTING_SUBSIDY],
+ nextStep:
+ "Subsidies should be provided to delegates to cover the gas fees for those who participate in governance voting.",
requirements: [
"The voting subsidy is not applied, requiring delegates to pay gas on the proposals they vote on.",
"With no voting subsidy, the structure is more vulnerable to spam attacks, as it's more costly for the defense than the attacker",
"The Foundation is the only allowed proposer, so the risk of spam attacks are low. Still, the DAO should consider applying a voting subsidy to make its structure more resilient.",
],
- riskExplanation:
- "The voting subsidy is not applied, requiring delegates to pay gas on the proposals they vote on.",
},
},
},
resilienceStages: true,
tokenDistribution: true,
dataTables: true,
+ attackExposure: {
+ defenseAreas: {
+ [RiskAreaEnum.SPAM_RESISTANCE]: {
+ description:
+ "A low proposal threshold and unrestricted proposal submissions reduce the cost of flooding governance, while the absence of voting subsidies limits defensive participation during a 5-day voting period, resulting in high exposure to governance spam.",
+ },
+ [RiskAreaEnum.ECONOMIC_SECURITY]: {
+ description:
+ "Economic security data is not yet available. Our team is actively working to integrate it.",
+ },
+ [RiskAreaEnum.SAFEGUARDS]: {
+ description:
+ "Voting is not subsidized, requiring delegates to pay to participate, which can reduce defensive turnout and weaken governance safeguards during critical proposals.",
+ },
+ [RiskAreaEnum.CONTRACT_SAFETY]: {
+ description: "All metrics in this defense are currently in low risk.",
+ },
+ [RiskAreaEnum.RESPONSE_TIME]: {
+ description:
+ "Response time is partially limited by shorter-than-ideal voting delay and voting period, reducing the window for coordinated reaction and review.",
+ },
+ [RiskAreaEnum.GOV_FRONTEND_RESILIENCE]: {
+ description:
+ "Interface protections are present but not fully hardened, and immutable votes limit recovery in the event of front-end compromise, resulting in moderate governance interface risk.",
+ },
+ },
+ },
};
diff --git a/apps/dashboard/shared/dao-config/nouns.ts b/apps/dashboard/shared/dao-config/nouns.ts
index c173e895b..5705e32cb 100644
--- a/apps/dashboard/shared/dao-config/nouns.ts
+++ b/apps/dashboard/shared/dao-config/nouns.ts
@@ -5,6 +5,8 @@ import { NounsIcon } from "@/shared/components/icons";
import { mainnet } from "viem/chains";
import { MainnetIcon } from "@/shared/components/icons/MainnetIcon";
import { MetricTypesEnum } from "@/shared/types/enums/metric-type";
+import { RECOMMENDED_SETTINGS } from "@/shared/constants/recommended-settings";
+import { RiskAreaEnum } from "@/shared/types/enums/RiskArea";
export const NOUNS: DaoConfiguration = {
name: "Nouns",
@@ -52,183 +54,267 @@ export const NOUNS: DaoConfiguration = {
// Fields are sorted alphabetically by GovernanceImplementationEnum for readability
fields: {
[GovernanceImplementationEnum.AUDITED_CONTRACTS]: {
- value: "Yes",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.AUDITED_CONTRACTS
].description,
- riskExplanation: "Nouns contracts are audited.",
+ currentSetting:
+ "Nouns DAO contracts have been audited, and the audit is publicly available.",
+ impact:
+ "With its governance contracts audited, the risk of vulnerabilities in them is minimized.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.AUDITED_CONTRACTS],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.INTERFACE_HIJACK]: {
- value: "No",
riskLevel: RiskLevel.HIGH,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.INTERFACE_HIJACK
].description,
+ currentSetting:
+ "The governance interfaces and domain of the Optimism DAO do not have DNS protection, leaving voters vulnerable to spoofing and hijacking attacks.",
+ impact:
+ "Without protection for its governance domains and interfaces, governance participants may be manipulated into voting for an outcome that harms the DAO.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.INTERFACE_HIJACK],
+ nextStep:
+ "Nouns needs to enable DNSSEC and HTTPS on the domains of its governance interfaces, in order to raise its standard to Medium Risk.",
requirements: [
"Without the proper protections(DNSSEC/SPF/DKIM/DMARC), attackers can spoof governance UIs by hijacking unprotected domains.",
],
- riskExplanation:
- "The domain is not signed with a valid signature (DNSSEC) and it is not possible to establish a secure connection to it (HTTPS).",
},
// Quantify the profitability of an attack on Nouns.
[GovernanceImplementationEnum.ATTACK_PROFITABILITY]: {
- value: "",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.ATTACK_PROFITABILITY
].description,
+ currentSetting:
+ "Nouns has a liquid treasury, but since there is no market liquidity to buy the tokens, the profitability of an attack depends on the DAO's auctions.",
+ impact:
+ "An attack on Nouns is not profitable under the current system, which relies on governance token auctions and has low liquidity in the secondary market.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[
+ GovernanceImplementationEnum.ATTACK_PROFITABILITY
+ ],
+ nextStep: "The parameter is in its lowest-risk condition.",
requirements: [""],
- riskExplanation: "",
},
[GovernanceImplementationEnum.PROPOSAL_FLASHLOAN_PROTECTION]: {
- value: "Yes",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.PROPOSAL_FLASHLOAN_PROTECTION
].description,
- riskExplanation:
- "Voting power are based on block previous to when voters could first cast a vote, making flashloan votes impossible.",
+ currentSetting:
+ "It protects the DAO from a flash loan aimed at reaching the Proposal Threshold and submitting a proposal, by taking a snapshot of the governance power from delegates/holders one block before the proposal submission.",
+ impact:
+ "It is not possible to use a flash loan to reach the amount required to submit a proposal.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[
+ GovernanceImplementationEnum.PROPOSAL_FLASHLOAN_PROTECTION
+ ],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.PROPOSAL_THRESHOLD]: {
- value: "30% Market Supply",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.PROPOSAL_THRESHOLD
].description,
- riskExplanation:
- "The supply available for purchase of governance tokens is extremely low—and the proposal threshold is high in relation to it.",
- },
- [GovernanceImplementationEnum.PROPOSAL_THRESHOLD_CANCEL]: {
- value: "Yes",
- riskLevel: RiskLevel.LOW,
- description:
- GOVERNANCE_IMPLEMENTATION_CONSTANTS[
- GovernanceImplementationEnum.PROPOSAL_THRESHOLD_CANCEL
- ].description,
- riskExplanation:
- "Nouns has a cancellation mechanism in place in case the balance of the person submitting a proposal falls below the proposal threshold.",
+ currentSetting:
+ "The Proposal Threshold is set to 3 $UNI (30% Market Supply)",
+ impact:
+ "The current liquidity of the governance token does not pose a risk to the DAO. Therefore, the Proposal Threshold is sufficient to block proposal spam and discourage attackers.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.PROPOSAL_THRESHOLD],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.SECURITY_COUNCIL]: {
- value: "No",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.SECURITY_COUNCIL
].description,
- riskExplanation:
+ currentSetting:
+ "Nouns does not have a Security Council, but it does have protection mechanisms—a Veto Strategy and the Proposal Threshold Cancel.",
+ impact:
"Nouns does not have a Security Council, but it does have protection mechanisms—a Veto Strategy and the Proposal Threshold Cancel.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.SECURITY_COUNCIL],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.SPAM_RESISTANCE]: {
- value: "YES",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.SPAM_RESISTANCE
].description,
- riskExplanation:
+ currentSetting:
"Nouns prevents the same address from submitting multiple proposals in governance.",
+ impact:
+ "The same address cannot submit multiple proposals in governance.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.SPAM_RESISTANCE],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.TIMELOCK_ADMIN]: {
- value: "Yes",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.TIMELOCK_ADMIN
].description,
- riskExplanation: "The Timelock is controlled by the Governor.",
+ currentSetting: "The Timelock is controlled by the Governor.",
+ impact:
+ "Since the Governor is the administrator of the Timelock, only the DAO can control it - decentralizing its governance.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.TIMELOCK_ADMIN],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.TIMELOCK_DELAY]: {
- value: "2 days",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.TIMELOCK_DELAY
].description,
- riskExplanation: "Two days is a sufficient delay for Timelock.",
+ currentSetting:
+ "The Timelock execution delay for an approved proposal is 2 days.",
+ impact:
+ "There is a protected delay between proposal approval and execution.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.TIMELOCK_DELAY],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.VETO_STRATEGY]: {
- value: "Yes",
riskLevel: RiskLevel.MEDIUM,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VETO_STRATEGY
].description,
+ currentSetting:
+ "Nouns has a veto strategy in place, but only the Foundation can veto proposals. In the documentation, the veto is attributed to DUNA, but no one responsible for the veto has been named yet.",
+ impact: "The veto prevents malicious proposals from being approved.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VETO_STRATEGY],
+ nextStep:
+ "The veto should be controlled by a Council chosen by the DAO, and the person responsible for vetoing proposals should be appointed.",
requirements: [
"To move up to Stage 2 (low risk), the veto strategy needs to be controlled by the DAO, not by a Foundation/DUNA. ",
],
- riskExplanation:
- "Nouns has a veto strategy in place, but only the Foundation can veto proposals. In the documentation, the veto is attributed to DUNA, but no one responsible for the veto has been named yet.",
},
[GovernanceImplementationEnum.VOTE_MUTABILITY]: {
- value: "No",
riskLevel: RiskLevel.MEDIUM,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VOTE_MUTABILITY
].description,
+ currentSetting:
+ "The DAO does not allow changing votes once they have been cast.",
+ impact:
+ "Governance participants cannot change their votes after casting them. In the event of a governance interface hijack, they may be manipulated into voting for the opposite of their intended choice, enabling an attack on the DAO.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VOTE_MUTABILITY],
+ nextStep:
+ "Allow voters to change their vote until the Voting Period ends.",
requirements: [
"Nouns must allow votes to be changed even after they have been cast in order to reach Stage 2. .",
],
- riskExplanation:
- "The lack of vote mutability jeopardizes DAO decisions if its main voting interface is attacked.",
},
// Review this
[GovernanceImplementationEnum.VOTING_DELAY]: {
- value: "12 hours",
riskLevel: RiskLevel.HIGH,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VOTING_DELAY
].description,
+ currentSetting: "The Voting Delay is set to 12 hours",
+ impact:
+ "The Voting Delay period can be longer. This gives delegates and stakeholders little time to coordinate their votes and for the DAO to protect itself against an attack. This poses a governance risk.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VOTING_DELAY],
+ nextStep: "The Voting Delay should be at least two days.",
requirements: [
"Nouns must have a voting delay of at least 2 days to be classified as Stage 1 (medium risk).",
],
- riskExplanation:
- "The 12-hour voting delay is too short for the DAO to protect itself from an attack before voting begins.",
},
[GovernanceImplementationEnum.VOTING_FLASHLOAN_PROTECTION]: {
- value: "Yes",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VOTING_FLASHLOAN_PROTECTION
].description,
- riskExplanation:
- "Voting power are based on block previous to when voters could first cast a vote, making flashloan votes impossible.",
+ currentSetting:
+ "It protects the DAO from a flash loan aimed to increase their voting power, by taking a snapshot of the governance power from delegates/holders one block before the Voting Period starts",
+ impact:
+ "It is not possible to use a flash loan to increase voting power and approve a proposal.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[
+ GovernanceImplementationEnum.VOTING_FLASHLOAN_PROTECTION
+ ],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.VOTING_PERIOD]: {
- value: "4 days",
riskLevel: RiskLevel.MEDIUM,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VOTING_PERIOD
].description,
+ currentSetting: "The Voting Period is set to 4 days",
+ impact:
+ "The current Voting Period is sufficient for governance participants to cast their votes.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VOTING_PERIOD],
+ nextStep: "The parameter is in its lowest-risk condition.",
requirements: [
"The voting period is 4 days, with the recommended safety being of 7 or more for a low level of risk.",
],
- riskExplanation:
- "The voting period is 4 days, with the recommended safety being of 7 or more for a low level of risk.",
},
[GovernanceImplementationEnum.VOTING_SUBSIDY]: {
- value: "Yes",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VOTING_SUBSIDY
].description,
- riskExplanation:
- "Nouns subsidizes the cost of votes for participants in governance.",
+ currentSetting:
+ "There is a subsidy to help voters participate in governance voting.",
+ impact:
+ "By subsidizing governance participants' voting costs, there is greater participation and stronger incentives for delegates to protect the DAO, since they do not incur gas fees to vote.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VOTING_SUBSIDY],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
},
},
- riskAnalysis: true,
resilienceStages: true,
tokenDistribution: true,
dataTables: true,
+ attackExposure: {
+ defenseAreas: {
+ [RiskAreaEnum.SPAM_RESISTANCE]: {
+ description:
+ "Voting period is below the ideal length, moderately reducing resistance to sustained proposal spam.",
+ },
+ [RiskAreaEnum.ECONOMIC_SECURITY]: {
+ description: "All metrics in this defense are currently in low risk.",
+ },
+ [RiskAreaEnum.SAFEGUARDS]: {
+ description:
+ "Veto authority exists but is centralized in the Foundation, creating moderate centralization and transparency risk.",
+ },
+ [RiskAreaEnum.CONTRACT_SAFETY]: {
+ description: "All metrics in this defense are currently in low risk.",
+ },
+ [RiskAreaEnum.RESPONSE_TIME]: {
+ description:
+ "A 12-hour voting delay and a 4-day voting period limit the time available for coordination and response, increasing the risk of rushed or insufficiently reviewed governance decisions.",
+ },
+ [RiskAreaEnum.GOV_FRONTEND_RESILIENCE]: {
+ description:
+ "Interface protections are largely present but not fully hardened, and immutable votes limit recovery in the event of front-end compromise, resulting in moderate governance interface risk.",
+ },
+ },
+ },
};
diff --git a/apps/dashboard/shared/dao-config/obol.ts b/apps/dashboard/shared/dao-config/obol.ts
index a6150082b..74a61243d 100644
--- a/apps/dashboard/shared/dao-config/obol.ts
+++ b/apps/dashboard/shared/dao-config/obol.ts
@@ -5,6 +5,8 @@ import { QUORUM_CALCULATION_TYPES } from "@/shared/constants/labels";
import { ObolIcon } from "@/shared/components/icons";
import { mainnet } from "viem/chains";
import { MainnetIcon } from "@/shared/components/icons/MainnetIcon";
+import { RECOMMENDED_SETTINGS } from "@/shared/constants/recommended-settings";
+import { RiskAreaEnum } from "@/shared/types/enums/RiskArea";
export const OBOL: DaoConfiguration = {
name: "Obol Collective",
@@ -43,197 +45,284 @@ export const OBOL: DaoConfiguration = {
attackProfitability: {
riskLevel: RiskLevel.LOW,
},
- riskAnalysis: true,
governanceImplementation: {
fields: {
[GovernanceImplementationEnum.AUDITED_CONTRACTS]: {
- value: "No",
riskLevel: RiskLevel.HIGH,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.AUDITED_CONTRACTS
].description,
+ currentSetting:
+ "The governance contracts in Obol have not been audited.",
+ impact:
+ "Obol's governance contracts have no public audit, making them a potential attack vector for hackers.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.AUDITED_CONTRACTS],
+ nextStep:
+ "Obol’s governance contracts should be audited, and the audit should be made public.",
requirements: [
"Governance contracts must be audited by a reputable third-party security firm and the audit report should be publicly available.",
],
- riskExplanation:
- "Governance contracts are not audited, or not publicly disclosed.",
},
[GovernanceImplementationEnum.INTERFACE_HIJACK]: {
- value: "Insufficient Protections",
riskLevel: RiskLevel.HIGH,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.INTERFACE_HIJACK
].description,
+ currentSetting:
+ "The governance interfaces and domain of the Obol do not have DNS protection, leaving voters vulnerable to spoofing and hijacking attacks.",
+ impact:
+ "Without protection for its governance domains and interfaces, governance participants may be manipulated into voting for an outcome that harms the DAO.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.INTERFACE_HIJACK],
+ nextStep:
+ "Obol needs to enable DNSSEC and HTTPS on the domains of its governance interfaces, in order to raise its standard to Medium Risk.",
requirements: [
"Voting domain must have CAA set up to prevent domain hijacking.",
],
- riskExplanation:
- "While a domain can function without a CAA record, but it is less secure because any certificate authority (CA) can issue certificates for that domain, creating a risk of fraudulent certificates, impersonation, and man-in-the-middle attacks.",
},
[GovernanceImplementationEnum.ATTACK_PROFITABILITY]: {
- value: "No Treasury Control",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.ATTACK_PROFITABILITY
].description,
- riskExplanation:
- "The DAO has no treasury directly controllable by governance, so there is no risk of attack profitability.",
+ currentSetting:
+ "The DAO does not have control over the treasury. Therefore, there is no risk of capturing it.",
+ impact:
+ "The DAO does not control the treasury. Therefore, its treasury can't be targeted in an attack.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[
+ GovernanceImplementationEnum.ATTACK_PROFITABILITY
+ ],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.PROPOSAL_FLASHLOAN_PROTECTION]: {
- value: "Yes",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.PROPOSAL_FLASHLOAN_PROTECTION
].description,
- riskExplanation:
- "Voting power is based on block previous to when voters could first cast a vote, making flashloan votes impossible.",
+ currentSetting:
+ "It protects the DAO from a flash loan aimed at reaching the Proposal Threshold and submitting a proposal, by taking a snapshot of the governance power from delegates/holders one block before the proposal submission.",
+ impact:
+ "It is not possible to use a flash loan to reach the amount required to submit a proposal.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[
+ GovernanceImplementationEnum.PROPOSAL_FLASHLOAN_PROTECTION
+ ],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.PROPOSAL_THRESHOLD]: {
- value: "30K $OBOL (0.006% Total Supply)",
riskLevel: RiskLevel.HIGH,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.PROPOSAL_THRESHOLD
].description,
+ currentSetting:
+ "The Proposal Threshold is set to 30K $OBOL (0,084% Total Supply)",
+ impact:
+ "The current liquidity of the governance token does not pose a risk to the DAO. Therefore, the Proposal Threshold is sufficient to block proposal spam and discourage attackers.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.PROPOSAL_THRESHOLD],
+ nextStep:
+ "The Proposal Threshold can be increased to a value above 0,5% market supply, in order to raise the cost of submitting proposals in governance and reduce the likelihood of spam.",
requirements: [
"Proposal threshold should be at least 1% of the active market supply to provide adequate protection against spam and malicious proposals.",
],
- riskExplanation:
- "The proposal threshold is less than 1% of the active market supply of $OBOL.",
- },
- [GovernanceImplementationEnum.PROPOSAL_THRESHOLD_CANCEL]: {
- value: "No",
- riskLevel: RiskLevel.HIGH,
- description:
- GOVERNANCE_IMPLEMENTATION_CONSTANTS[
- GovernanceImplementationEnum.PROPOSAL_THRESHOLD_CANCEL
- ].description,
- requirements: [
- "The DAO must enforce a permissionless way to cancel any live proposal if the proposer's voting power drops below the proposal-creation threshold.",
- ],
- riskExplanation:
- "Once a proposal is submitted, the proposer can immediately dump their tokens, reducing their financial risk in case of an attack.",
},
[GovernanceImplementationEnum.SECURITY_COUNCIL]: {
- value: "Yes",
riskLevel: RiskLevel.HIGH,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.SECURITY_COUNCIL
].description,
+ currentSetting:
+ "As of now, Obol Collective functions with a small committee multi-sig (2/3) but intends to develop towards a full Security Council structure. Treasury is not controlled by governance, but malicious proposals may still pose a risk to the protocol and its users.",
+ impact:
+ "Having an insecure Security Council puts not only the DAO, but the protocol itself at risk. If the 2/3 multisig is compromised, Obol could be attacked, affecting its users.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.SECURITY_COUNCIL],
+ nextStep:
+ "The Security Council should follow L2Beat standards, with a multisig of at least 8 signers and a 75% approval threshold for signatures.",
requirements: [
"The Obol Security Council must upgrade its multisig to the highest standard, with at least 8 signers and a 75% approval threshold for transactions.",
],
- riskExplanation:
- "As of now, Obol Collective functions with a small committee multi-sig (2/3) but intends to develop towards a full Security Council structure. Treasury is not controlled by governance, but malicious proposals may still pose a risk to the protocol and its users.",
},
[GovernanceImplementationEnum.SPAM_RESISTANCE]: {
- value: "No",
riskLevel: RiskLevel.HIGH,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.SPAM_RESISTANCE
].description,
+ currentSetting:
+ "There is no limit to the number of proposals that a single address can submit in the DAO.",
+ impact:
+ "A single address can submit multiple proposals, potentially masking an attack within one of them.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.SPAM_RESISTANCE],
+ nextStep:
+ "It is necessary to limit the number of proposals that can be submitted by a single address.",
requirements: [
"Obol has no limit on active proposals or proposals submitted per address. Thus, it is susceptible to spam in its governance.",
],
- riskExplanation: "Obol governance is vulnerable to spam.",
},
[GovernanceImplementationEnum.TIMELOCK_ADMIN]: {
- value: "Obol Governor",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.TIMELOCK_ADMIN
].description,
- riskExplanation:
- "Obol Governor has admin rights for proposing, executing, and cancelling proposals, which is a standard and secure setup for DAO governance.",
+ currentSetting: "Governor has Admin role on timelock",
+ impact:
+ "Since the Governor is the administrator of the Timelock, only the DAO can control it - decentralizing its governance.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.TIMELOCK_ADMIN],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.TIMELOCK_DELAY]: {
- value: "5 days",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.TIMELOCK_DELAY
].description,
- riskExplanation: "The timelock delay is longer than 1 day",
+ currentSetting:
+ "The Timelock execution delay for an approved proposal is 5 days.",
+ impact:
+ "There is a protected delay between proposal approval and execution.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.TIMELOCK_DELAY],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.VETO_STRATEGY]: {
- value: "Yes",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VETO_STRATEGY
].description,
- riskExplanation:
+ currentSetting:
"Governor has veto powers over the timelock, providing an additional layer of security against malicious proposals.",
+ impact:
+ "It is possible to cancel proposals through the Timelock or the Security Council.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VETO_STRATEGY],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.VOTE_MUTABILITY]: {
- value: "No",
riskLevel: RiskLevel.MEDIUM,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VOTE_MUTABILITY
].description,
+ currentSetting:
+ "The DAO does not allow changing votes once they have been cast.",
+ impact:
+ "Governance participants cannot change their votes after casting them. In the event of a governance interface hijack, they may be manipulated into voting for the opposite of their intended choice, enabling an attack on the DAO.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VOTE_MUTABILITY],
+ nextStep:
+ "Allow voters to change their vote until the Voting Period ends.",
requirements: [
"Without the ability to change votes, voters cannot correct mistakes or respond to new information, potentially leading to suboptimal governance outcomes.",
],
- riskExplanation:
- "Votes cannot be changed once cast, which can lead to suboptimal governance outcomes if voters make mistakes or if new information arises after voting has begun.",
},
[GovernanceImplementationEnum.VOTING_DELAY]: {
- value: "1 day",
riskLevel: RiskLevel.HIGH,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VOTING_DELAY
].description,
+ currentSetting: "The Voting Delay is set to 1 day.",
+ impact:
+ "With a short Voting Delay, delegates and stakeholders have little time to prepare to vote or to protect the DAO from an attack.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VOTING_DELAY],
+ nextStep:
+ "The Voting Delay needs to be increased to at least 2 days in order to be considered Medium Risk.",
requirements: [
"A minimum of 2 days of Voting Delay is required for a DAO to be considered secure in this parameter.",
],
- riskExplanation:
- "With such a low voting delay, the DAO does not have time to mobilize voters to protect itself from a potential attack.",
},
[GovernanceImplementationEnum.VOTING_FLASHLOAN_PROTECTION]: {
- value: "Yes",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VOTING_FLASHLOAN_PROTECTION
].description,
- riskExplanation:
- "Voting power is based on the proposal snapshot timepoint, making flashloan votes impossible.",
+ currentSetting:
+ "It protects the DAO from a flash loan aimed to increase their voting power, by taking a snapshot of the governance power from delegates/holders one block before the Voting Period starts",
+ impact:
+ "It is not possible to use a flash loan to increase voting power and approve a proposal.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[
+ GovernanceImplementationEnum.VOTING_FLASHLOAN_PROTECTION
+ ],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.VOTING_PERIOD]: {
- value: "5 days",
riskLevel: RiskLevel.MEDIUM,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VOTING_PERIOD
].description,
+ currentSetting: "The Voting Period is set to 5 days.",
+ impact:
+ "The current Voting Period is sufficient for governance participants to cast their votes.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VOTING_PERIOD],
+ nextStep:
+ "The Voting Period should be increased to 7 days in order to be considered Low Risk.",
requirements: [
"Voting period should be at least 7 days to allow adequate time for community discussion and participation.",
],
- riskExplanation:
- "Short voting period may compromise quality of governance decisions by limiting time available for community-wide discussion and participation.",
},
[GovernanceImplementationEnum.VOTING_SUBSIDY]: {
- value: "Yes",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VOTING_SUBSIDY
].description,
- riskExplanation:
- "Obol Collective has a voting subsidy mechanism in place to reimburse voters for gas costs incurred when voting on proposals, but it is not active as of now.",
+ currentSetting:
+ "There is a subsidy to help voters participate in governance voting.",
+ impact:
+ "By subsidizing governance participants' voting costs, there is greater participation and stronger incentives for delegates to protect the DAO, since they do not incur gas fees to vote.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VOTING_SUBSIDY],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
},
},
resilienceStages: true,
tokenDistribution: true,
dataTables: true,
+ attackExposure: {
+ defenseAreas: {
+ [RiskAreaEnum.SPAM_RESISTANCE]: {
+ description:
+ "A low proposal threshold and unrestricted proposal submissions reduce the cost of flooding governance, while a 5-day voting period limits defensive participation, resulting in high exposure to governance spam.",
+ },
+ [RiskAreaEnum.ECONOMIC_SECURITY]: {
+ description:
+ "The treasury is controlled by a multisig, not executed automatically by governance. Since proposals can’t directly move funds, attacks that try to profit by draining the treasury don’t apply.",
+ },
+ [RiskAreaEnum.SAFEGUARDS]: {
+ description:
+ "Safeguards rely on a limited committee structure, increasing exposure to malicious actions or governance mistakes.",
+ },
+ [RiskAreaEnum.CONTRACT_SAFETY]: {
+ description:
+ "Governance contracts have not been audited, increasing the risk that vulnerabilities in smart contracts or governance processes could be exploited.",
+ },
+ [RiskAreaEnum.RESPONSE_TIME]: {
+ description:
+ "A 1-day voting delay and a 5-day voting period limit the time available for coordination and response, increasing the risk of rushed or insufficiently reviewed governance decisions.",
+ },
+ [RiskAreaEnum.GOV_FRONTEND_RESILIENCE]: {
+ description:
+ "Interface protections are largely absent, leaving governance interfaces vulnerable to spoofing and hijacking, and immutable votes limit recovery from front-end compromise, resulting in high governance interface risk.",
+ },
+ },
+ },
};
diff --git a/apps/dashboard/shared/dao-config/op.ts b/apps/dashboard/shared/dao-config/op.ts
index 1309be10a..f72d725b0 100644
--- a/apps/dashboard/shared/dao-config/op.ts
+++ b/apps/dashboard/shared/dao-config/op.ts
@@ -5,6 +5,8 @@ import { OptimismIcon } from "@/shared/components/icons";
import { optimism } from "viem/chains";
import { QUORUM_CALCULATION_TYPES } from "@/shared/constants/labels";
import { OptimismChainIcon } from "@/shared/components/icons/OptimismChainIcon";
+import { RECOMMENDED_SETTINGS } from "@/shared/constants/recommended-settings";
+import { RiskAreaEnum } from "@/shared/types/enums/RiskArea";
export const OP: DaoConfiguration = {
name: "Optimism",
@@ -47,205 +49,287 @@ export const OP: DaoConfiguration = {
percentage: 0.3,
},
},
- riskAnalysis: true,
governanceImplementation: {
// Fields are sorted alphabetically by GovernanceImplementationEnum for readability
fields: {
[GovernanceImplementationEnum.AUDITED_CONTRACTS]: {
- value: "Yes",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.AUDITED_CONTRACTS
].description,
- riskExplanation:
- "The contracts, provided by Agora.xyz, have been audited for smart contract security.",
+ currentSetting:
+ "The Optimism DAO contracts have been audited, and the audit is publicly available.",
+ impact:
+ "With its governance contracts audited, the risk of vulnerabilities in them is minimized.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.AUDITED_CONTRACTS],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.INTERFACE_HIJACK]: {
- value: "No",
riskLevel: RiskLevel.HIGH,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.INTERFACE_HIJACK
].description,
+ currentSetting:
+ "The governance interfaces and domain of the Optimism DAO do not have DNS protection, leaving voters vulnerable to spoofing and hijacking attacks.",
+ impact:
+ "Without protection for its governance domains and interfaces, governance participants may be manipulated into voting for an outcome that harms the DAO.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.INTERFACE_HIJACK],
+ nextStep:
+ "Optimism needs to enable DNSSEC and HTTPS on the domains of its governance interfaces, in order to raise its standard to Medium Risk.",
requirements: [
"Without the proper protections(DNSSEC/SPF/DKIM/DMARC), attackers can spoof governance UIs by hijacking unprotected domains.",
"Currently, the DAO’s domains have no publicly verifiable DNS-level protections (High Risk).",
"Secure every DAO‑owned domain with Industry standard and publish a security‑contact record.",
],
- riskExplanation:
- "The DAO's domains have no publicly verifiable DNS-level protections we are aware of.",
},
[GovernanceImplementationEnum.ATTACK_PROFITABILITY]: {
- value: "No Treasury Control",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.ATTACK_PROFITABILITY
].description,
+ currentSetting:
+ "The Optimism treasury is not accessible to the DAO; it is controlled only by Foundation-managed multisigs. Therefore, there is no opportunity to profit from an attack on the treasury.",
+ impact:
+ "The DAO does not control the treasury. Therefore, its treasury can't be targeted in an attack.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[
+ GovernanceImplementationEnum.ATTACK_PROFITABILITY
+ ],
+ nextStep: "The parameter is in its lowest-risk condition.",
requirements: [
"The DAO has no treasury directly controllable by governance, so there is no risk of attack profitability.",
"The treasury risks in the Collective are related to mistakes or malicious actions by the Foundation.",
],
- riskExplanation:
- "The DAO has no treasury directly controllable by governance, so there is no way to calculate attack profitability.",
},
[GovernanceImplementationEnum.PROPOSAL_FLASHLOAN_PROTECTION]: {
- value: "Only Foundation Proposes",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.PROPOSAL_FLASHLOAN_PROTECTION
].description,
+ currentSetting:
+ "It protects the DAO from a flash loan aimed at reaching the Proposal Threshold and submitting a proposal, by taking a snapshot of the governance power from delegates/holders one block before the proposal submission.",
+ impact:
+ "It is not possible to use a flash loan to reach the amount required to submit a proposal.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[
+ GovernanceImplementationEnum.PROPOSAL_FLASHLOAN_PROTECTION
+ ],
+ nextStep: "The parameter is in its lowest-risk condition.",
requirements: [
"The Foundation, as manager of the contract, is the only one that can propose, so there's no risk of proposal flashloan attacks.",
"The flashloan protection in the contract is commented out, due to the onlyManagerOrTimelock bein used on the propose() function.",
],
- riskExplanation:
- "The Foundation, as manager of the contract, is the only one that can propose, so there's no risk of proposal flashloan attacks.",
},
[GovernanceImplementationEnum.PROPOSAL_THRESHOLD]: {
- value: "Only Foundation Proposes",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.PROPOSAL_THRESHOLD
].description,
+ currentSetting:
+ "Since only the Foundation can submit proposals, there is no Proposal Threshold.",
+ impact:
+ "There is no impact from not having a Proposal Threshold, as long as only the Foundation holds this power.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.PROPOSAL_THRESHOLD],
+ nextStep: "The parameter is in its lowest-risk condition.",
requirements: [
"The proposal threshold is 0, but the propose() function is only callable by the manager, which is the Foundation.",
],
- riskExplanation:
- "The proposal threshold is 0, but the propose() function is only callable by the manager, which is the Foundation. All proposals are made in the forum and brought onchain by a centralized manager.",
- },
- [GovernanceImplementationEnum.PROPOSAL_THRESHOLD_CANCEL]: {
- value: "Only Foundation Can Cancel",
- riskLevel: RiskLevel.LOW,
- description:
- GOVERNANCE_IMPLEMENTATION_CONSTANTS[
- GovernanceImplementationEnum.PROPOSAL_THRESHOLD_CANCEL
- ].description,
- requirements: [
- "Only the manager, timelock or proposer can cancel a proposal. As the manager is also the only possible proposer, this means only the manager (OP Foundation) can propose or cancel proposals.",
- ],
- riskExplanation:
- "The proposal cancel function is only callable by the manager, which is the Foundation.",
},
[GovernanceImplementationEnum.SECURITY_COUNCIL]: {
- value: "Yes",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.SECURITY_COUNCIL
].description,
- riskExplanation:
- "The Security Council is elected in 2 separate cohorts of members that are responsible for the security of the DAO. The Security Council is not active on DAO governance, but directly on protocol upgrades.",
+ currentSetting:
+ "Optimism has a Security Council, elected by the DAO and renewed periodically. It is not responsible for participating in governance decisions, but for performing protocol upgrades.",
+ impact:
+ "The Security Council can cancel L2 upgrades, protecting the protocol from governance-level attacks.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.SECURITY_COUNCIL],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.SPAM_RESISTANCE]: {
- value: "Does not apply",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.SPAM_RESISTANCE
].description,
- riskExplanation:
- "The Foundation is both the only allowed proposer and the treasury manager, so there's no risk of a spam attack given that any compromise to the foundation would lead directly to a treasury drain.",
+ currentSetting:
+ "There is no limit to the number of proposals that a single address can submit in the DAO.",
+ impact:
+ "A single address can submit multiple proposals, potentially masking an attack within one of them.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.SPAM_RESISTANCE],
+ nextStep:
+ "It is necessary to limit the number of proposals that can be submitted by a single address.",
},
[GovernanceImplementationEnum.TIMELOCK_ADMIN]: {
- value: "No",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.TIMELOCK_ADMIN
].description,
- riskExplanation:
- "The timelock holds no assets and is not used for governance execution.",
+ currentSetting:
+ "There is a Timelock, but it is not used and is controlled by the Foundation.",
+ impact: "There is no impact, since the Timelock is not used.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.TIMELOCK_ADMIN],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.TIMELOCK_DELAY]: {
- value: "Does not apply",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.TIMELOCK_DELAY
].description,
- riskExplanation: "The timelock is not used for governance execution.",
+ currentSetting:
+ "The DAO does not have the ability to execute proposals, nor a Timelock to provide a delay between approval and execution.",
+ impact:
+ "Since Optimism does not have a Timelock connected to its Governor, there is no impact.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.TIMELOCK_DELAY],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.VETO_STRATEGY]: {
- value: "Does not apply",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VETO_STRATEGY
].description,
- riskExplanation:
- "Proposals are not executed by the timelock, but by the Foundation's multisig, so the Foundation can veto proposals by calling the cancel() function during voting, or by just not executing the proposal after approved.",
+ currentSetting:
+ "Since only the Foundation can submit and execute proposals, there is no need for a Veto Strategy.",
+ impact:
+ "There is no impact from not having a Veto Strategy, as long as only the Foundation has the power to propose and execute proposals.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VETO_STRATEGY],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.VOTE_MUTABILITY]: {
- value: "No",
riskLevel: RiskLevel.MEDIUM,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VOTE_MUTABILITY
].description,
+ currentSetting:
+ "The DAO does not allow changing votes once they have been cast.",
+ impact:
+ "Governance participants cannot change their votes after casting them. In the event of a governance interface hijack, they may be manipulated into voting for the opposite of their intended choice, enabling an attack on the DAO.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VOTE_MUTABILITY],
+ nextStep:
+ "Allow voters to change their vote until the Voting Period ends.",
requirements: [
"If voters cannot revise their ballots, a last-minute interface exploit or late discovery of malicious code can trap delegates in a choice that now favors an attacker, weakening the DAO’s defense.",
"The governance contract should let any voter overwrite their previous vote while the voting window is open—ideally through an adapted castVoteWithReasonAndParams call or equivalent.",
],
- riskExplanation:
- "In case of an exploit that affects the voting platforms, immutable votes can leave delegates stuck with a incorrect vote made in a compromised interface.",
},
[GovernanceImplementationEnum.VOTING_DELAY]: {
- value: "0 seconds",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VOTING_DELAY
].description,
+ currentSetting:
+ "The Foundation is the only allower proposer, and it follows a voting schedule, so there's no reason to have a voting delay. ",
+ impact:
+ "The Optimism voting calendar replaces the Voting Delay, since this structure is fully controlled by the Foundation.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VOTING_DELAY],
+ nextStep: "The parameter is in its lowest-risk condition.",
requirements: [
"Voting delay is the time between proposal submission and the snapshot that fixes voting power. The current 0 blocks delay means proposals are live for voting as soon as created by the Foundation.",
"The DAO should enforce a delay of at least two full days and have an automatic alert plan that notifies major voters the moment a proposal is posted.",
"The Foundation is the only allowed proposer, and it follows a voting schedule, so there's no reason to have a voting delay.",
],
- riskExplanation:
- "The Foundation is the only allowed proposer, and it follows a voting schedule, so there's no reason to have a voting delay.",
},
[GovernanceImplementationEnum.VOTING_FLASHLOAN_PROTECTION]: {
- value: "Yes",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VOTING_FLASHLOAN_PROTECTION
].description,
- riskExplanation:
- "Delegates voting power are based on its delegation on block previous to when they could first cast a vote, making flashloan votes impossible.",
+ currentSetting:
+ "It protects the DAO from a flash loan aimed to increase their voting power, by taking a snapshot of the governance power from delegates/holders one block before the Voting Period sarts",
+ impact:
+ "It is not possible to use a flash loan to increase voting power and approve a proposal.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[
+ GovernanceImplementationEnum.VOTING_FLASHLOAN_PROTECTION
+ ],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.VOTING_PERIOD]: {
- value: "6 days",
riskLevel: RiskLevel.MEDIUM,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VOTING_PERIOD
].description,
+ currentSetting: "The Voting Period is set to 6 days",
+ impact:
+ "The current Voting Period is sufficient for governance participants to cast their votes.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VOTING_PERIOD],
+ nextStep: "The parameter is in its lowest-risk condition.",
requirements: [
"The voting period is 6 days, with the recommended safety being of 7 or more for a low level of risk.",
"The Foundation is the only allowed proposer, and it follows a voting schedule, reducing the impact of this risk.",
],
- riskExplanation:
- "The voting period is 6 days, with the recommended safety being of 7 or more for a low level of risk.",
},
[GovernanceImplementationEnum.VOTING_SUBSIDY]: {
- value: "No",
riskLevel: RiskLevel.HIGH,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VOTING_SUBSIDY
].description,
+ currentSetting:
+ "There is no subsidy to help voters participate in governance voting.",
+ impact:
+ "Without subsidies, voters incur costs to participate in governance. During periods of high gas fees, participation may decrease, making the DAO easier to attack.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VOTING_SUBSIDY],
+ nextStep:
+ "Subsidies should be provided to delegates to cover the gas fees for those who participate in governance voting.",
requirements: [
"The voting subsidy is not applied, requiring delegates to pay gas on the proposals they vote on.",
"With no voting subsidy, the structure is more vulnerable to spam attacks, as it's more costly for the defense than the attacker",
"The Foundation is the only allowed proposer, so the risk of spam attacks are low. Still, the DAO should consider applying a voting subsidy to make its structure more resilient.",
],
- riskExplanation:
- "The voting subsidy is not applied, requiring delegates to pay gas on the proposals they vote on.",
+ },
+ },
+ },
+ attackExposure: {
+ defenseAreas: {
+ [RiskAreaEnum.SPAM_RESISTANCE]: {
+ description:
+ "Voting is not subsidized, requiring delegates to pay to participate, which can reduce turnout. Combined with a 6-day voting period, this limits visibility and response, increasing governance spam risk.",
+ },
+ [RiskAreaEnum.ECONOMIC_SECURITY]: {
+ description:
+ "The treasury is controlled by a multisig, not executed automatically by governance. Since proposals can’t directly move funds, attacks that try to profit by draining the treasury don’t apply.",
+ },
+ [RiskAreaEnum.SAFEGUARDS]: {
+ description:
+ "Voting is not subsidized, requiring delegates to pay to participate, which can reduce defensive turnout and weaken governance safeguards during critical proposals.",
+ },
+ [RiskAreaEnum.CONTRACT_SAFETY]: {
+ description: "All metrics in this defense are currently in low risk.",
+ },
+ [RiskAreaEnum.RESPONSE_TIME]: {
+ description:
+ "A 6-day voting period provides limited time for coordination and response, resulting in moderate response-time risk.",
+ },
+ [RiskAreaEnum.GOV_FRONTEND_RESILIENCE]: {
+ description:
+ "Interface protections are largely absent, leaving governance interfaces vulnerable to spoofing and hijacking, and immutable votes limit recovery from front-end compromise, resulting in high governance interface risk.",
},
},
},
diff --git a/apps/dashboard/shared/dao-config/scr.ts b/apps/dashboard/shared/dao-config/scr.ts
index d8a1133f8..dc9c59922 100644
--- a/apps/dashboard/shared/dao-config/scr.ts
+++ b/apps/dashboard/shared/dao-config/scr.ts
@@ -4,6 +4,8 @@ import { GOVERNANCE_IMPLEMENTATION_CONSTANTS } from "@/shared/constants/governan
import { ScrollIcon } from "@/shared/components/icons";
import { scroll } from "viem/chains";
import { QUORUM_CALCULATION_TYPES } from "@/shared/constants/labels";
+import { RECOMMENDED_SETTINGS } from "@/shared/constants/recommended-settings";
+import { RiskAreaEnum } from "@/shared/types/enums/RiskArea";
export const SCR: DaoConfiguration = {
name: "Scroll",
@@ -40,188 +42,269 @@ export const SCR: DaoConfiguration = {
attackProfitability: {
riskLevel: RiskLevel.LOW,
},
- riskAnalysis: true,
governanceImplementation: {
fields: {
[GovernanceImplementationEnum.AUDITED_CONTRACTS]: {
- value: "Yes",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.AUDITED_CONTRACTS
].description,
- riskExplanation: "Governance contracts are audited.",
+ currentSetting:
+ "The Scroll DAO contracts have been audited, and the audit is publicly available.",
+ impact:
+ "With its governance contracts audited, the risk of vulnerabilities in them is minimized.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.AUDITED_CONTRACTS],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.INTERFACE_HIJACK]: {
- value: "No",
riskLevel: RiskLevel.HIGH,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.INTERFACE_HIJACK
].description,
+ currentSetting:
+ "The governance interfaces and domain of the Scroll do not have DNS protection, leaving voters vulnerable to spoofing and hijacking attacks.",
+ impact:
+ "Without protection for its governance domains and interfaces, governance participants may be manipulated into voting for an outcome that harms the DAO.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.INTERFACE_HIJACK],
+ nextStep:
+ "Scroll needs to enable DNSSEC and HTTPS on the domains of its governance interfaces, in order to raise its standard to Medium Risk.",
requirements: [
"Without the proper protections(DNSSEC/SPF/DKIM/DMARC), attackers can spoof governance UIs by hijacking unprotected domains.",
"Secure every DAO‑owned domain with Industry standard and publish a security‑contact record.",
],
- riskExplanation:
- "The domain is not signed with a valid signature (DNSSEC) and it is not possible to establish a secure connection to it (HTTPS).",
},
[GovernanceImplementationEnum.ATTACK_PROFITABILITY]: {
- value: "No Treasury Control",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.ATTACK_PROFITABILITY
].description,
- riskExplanation:
- "The DAO has no treasury directly controllable by governance, so there is no risk of attack profitability.",
+ currentSetting:
+ "The DAO does not have control over the treasury. Therefore, there is no risk of capturing it.",
+ impact:
+ "The DAO does not control the treasury. Therefore, its treasury can't be targeted in an attack.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[
+ GovernanceImplementationEnum.ATTACK_PROFITABILITY
+ ],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.PROPOSAL_FLASHLOAN_PROTECTION]: {
- value: "Yes",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.PROPOSAL_FLASHLOAN_PROTECTION
].description,
- riskExplanation:
- "Voting power are based on block previous to when voters could first cast a vote, making flashloan votes impossible.",
+ currentSetting:
+ "It protects the DAO from a flash loan aimed at reaching the Proposal Threshold and submitting a proposal, by taking a snapshot of the governance power from delegates/holders one block before the proposal submission.",
+ impact:
+ "It is not possible to use a flash loan to reach the amount required to submit a proposal.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[
+ GovernanceImplementationEnum.PROPOSAL_FLASHLOAN_PROTECTION
+ ],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.PROPOSAL_THRESHOLD]: {
- value: "5% Total Supply",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.PROPOSAL_THRESHOLD
].description,
- riskExplanation:
- "The proposal threshold is greater than 1% of the active market supply of $SCR.",
- },
- [GovernanceImplementationEnum.PROPOSAL_THRESHOLD_CANCEL]: {
- value: "No",
- riskLevel: RiskLevel.HIGH,
- description:
- GOVERNANCE_IMPLEMENTATION_CONSTANTS[
- GovernanceImplementationEnum.PROPOSAL_THRESHOLD_CANCEL
- ].description,
- requirements: [
- "The DAO must enforce a permissionless way to cancel any live proposal if the proposer's voting power drops below the proposal-creation threshold.",
- ],
- riskExplanation:
- "Once a proposal is submitted, the proposer can immediately dump their tokens, reducing their financial risk in case of an attack.",
+ currentSetting:
+ "The Proposal Threshold is set to 50M $UNI (5% Total Supply)",
+ impact:
+ "The current liquidity of the governance token does not pose a risk to the DAO. Therefore, the Proposal Threshold is sufficient to block proposal spam and discourage attackers.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.PROPOSAL_THRESHOLD],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.SECURITY_COUNCIL]: {
- value: "No",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.SECURITY_COUNCIL
].description,
- riskExplanation:
- "Although it does not have a Security Council, the DAO has no control over Scroll's' capital. Therefore, there is no risk, because the DAO does not control anything.",
+ currentSetting: "Scroll has a Security Council",
+ impact:
+ "The Security Council can protect the DAO from malicious proposals by canceling them after the 9/12 multisig approval.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.SECURITY_COUNCIL],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.SPAM_RESISTANCE]: {
- value: "No",
riskLevel: RiskLevel.HIGH,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.SPAM_RESISTANCE
].description,
+ currentSetting:
+ "There is no limit to the number of proposals that a single address can submit in the DAO.",
+ impact:
+ "A single address can submit multiple proposals, potentially masking an attack within one of them.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.SPAM_RESISTANCE],
+ nextStep:
+ "It is necessary to limit the number of proposals that can be submitted by a single address.",
requirements: [
"Scroll has no limit on active proposals or proposals submitted per address. With a low proposal threshold, it is susceptible to spam in its governance.",
],
- riskExplanation: "Scroll governance is vulnerable to spam proposals.",
},
[GovernanceImplementationEnum.TIMELOCK_ADMIN]: {
- value: "Yes",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.TIMELOCK_ADMIN
].description,
- riskExplanation:
- "Governance powers fully enforced via Timelock, not upgradeable by EOA or central party",
+ currentSetting: "Governor has Admin role on timelock",
+ impact:
+ "Since the Governor is the administrator of the Timelock, only the DAO can control it - decentralizing its governance.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.TIMELOCK_ADMIN],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.TIMELOCK_DELAY]: {
- value: "3 days",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.TIMELOCK_DELAY
].description,
- riskExplanation: "The timelock delay is higher than 1 day.",
+ currentSetting:
+ "The Timelock execution delay for an approved proposal is 3 days.",
+ impact:
+ "There is a protected delay between proposal approval and execution.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.TIMELOCK_DELAY],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.VETO_STRATEGY]: {
- value: "Yes",
riskLevel: RiskLevel.MEDIUM,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VETO_STRATEGY
].description,
+ currentSetting:
+ "Scroll has the ability to veto proposals through its Security Council and via its Timelock (Governor).",
+ impact: "Scroll can veto malicious proposals with the Security Council",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VETO_STRATEGY],
+ nextStep:
+ "Only the DAO should be able to cancel proposals, not an external agent (such as a Security Council appointed by the Foundation).",
requirements: [
"Veto strategy should be fully controlled by the DAO in order to have a low risk level.",
],
- riskExplanation:
- "There is a veto strategy controlled by the Timelock itself and Security Council multisig.",
},
[GovernanceImplementationEnum.VOTE_MUTABILITY]: {
- value: "No",
riskLevel: RiskLevel.MEDIUM,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VOTE_MUTABILITY
].description,
+ currentSetting:
+ "The DAO does not allow changing votes once they have been cast.",
+ impact:
+ "Governance participants cannot change their votes after casting them. In the event of a governance interface hijack, they may be manipulated into voting for the opposite of their intended choice, enabling an attack on the DAO.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VOTE_MUTABILITY],
+ nextStep:
+ "Allow voters to change their vote until the Voting Period ends.",
requirements: [
"Without the ability to change votes after they are cast, voters cannot respond to new information or changes in sentiment.",
],
- riskExplanation:
- "The mutability of the vote is fundamental to allow voters to change their vote in response to new information or changes in sentiment.",
},
[GovernanceImplementationEnum.VOTING_DELAY]: {
- value: "3 days",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VOTING_DELAY
].description,
- riskExplanation:
- "With three days, Scroll has enough time to gather votes and delegates with the goal of blocking a malicious proposal in the DAO.",
+ currentSetting: "The Voting Delay is set to 3 days.",
+ impact:
+ "Given the current Voting Delay, the DAO has sufficient time to coordinate stakeholders and wallets before the snapshot (that counts votes) occurs.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VOTING_DELAY],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.VOTING_FLASHLOAN_PROTECTION]: {
- value: "Yes",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VOTING_FLASHLOAN_PROTECTION
].description,
- riskExplanation:
- "Voting power is based on block previous to when voters could first cast a vote, making flashloan votes impossible.",
+ currentSetting:
+ "It protects the DAO from a flash loan aimed to increase their voting power, by taking a snapshot of the governance power from delegates/holders one block before the Voting Period sarts",
+ impact:
+ "It is not possible to use a flash loan to increase voting power and approve a proposal.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[
+ GovernanceImplementationEnum.VOTING_FLASHLOAN_PROTECTION
+ ],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.VOTING_PERIOD]: {
- value: "7 days",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VOTING_PERIOD
].description,
- riskExplanation:
- "Seven days is enough time for the DAO to organize itself against an attack during the voting period.",
+ currentSetting: "The Voting Period is set to 7 days.",
+ impact:
+ "The current Voting Period is sufficient for governance participants to cast their votes.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VOTING_PERIOD],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.VOTING_SUBSIDY]: {
- value: "No",
riskLevel: RiskLevel.HIGH,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VOTING_SUBSIDY
].description,
+ currentSetting:
+ "There is no subsidy to help voters participate in governance voting.",
+ impact:
+ "Without subsidies, voters incur costs to participate in governance. During periods of high gas fees, participation may decrease, making the DAO easier to attack.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VOTING_SUBSIDY],
+ nextStep:
+ "Subsidies should be provided to delegates to cover the gas fees for those who participate in governance voting.",
requirements: [
"Introduce a voting subsidy mechanism to encourage higher voter turnout and reduce voter attrition in times of need.",
],
- riskExplanation:
- "The voting subsidy is not applied, requiring voters to pay gas on the proposals they vote on.",
},
},
},
resilienceStages: true,
tokenDistribution: true,
dataTables: true,
+ attackExposure: {
+ defenseAreas: {
+ [RiskAreaEnum.SPAM_RESISTANCE]: {
+ description:
+ "Proposal submissions are unrestricted, and voting is not subsidized, reducing defensive response and significantly increasing governance spam risk.",
+ },
+ [RiskAreaEnum.ECONOMIC_SECURITY]: {
+ description:
+ "Economic security data is not yet available. Our team is actively working to integrate it.",
+ },
+ [RiskAreaEnum.SAFEGUARDS]: {
+ description:
+ "Voting is not subsidized, reducing defensive participation and weakening safeguards despite the presence of veto mechanisms.",
+ },
+ [RiskAreaEnum.CONTRACT_SAFETY]: {
+ description: "All metrics in this defense are currently in low risk.",
+ },
+ [RiskAreaEnum.RESPONSE_TIME]: {
+ description: "All metrics in this defense are currently in low risk.",
+ },
+ [RiskAreaEnum.GOV_FRONTEND_RESILIENCE]: {
+ description:
+ "Interface protections are largely absent, leaving governance interfaces vulnerable to spoofing and hijacking, and immutable votes limit recovery from front-end compromise, resulting in high governance interface risk.",
+ },
+ },
+ },
};
diff --git a/apps/dashboard/shared/dao-config/types.ts b/apps/dashboard/shared/dao-config/types.ts
index 5a28a9cce..c5559d549 100644
--- a/apps/dashboard/shared/dao-config/types.ts
+++ b/apps/dashboard/shared/dao-config/types.ts
@@ -1,6 +1,10 @@
import { ReactNode, SVGProps } from "react";
import { Address, Chain } from "viem";
-import { RiskLevel, GovernanceImplementationEnum } from "@/shared/types/enums";
+import {
+ RiskLevel,
+ GovernanceImplementationEnum,
+ RiskAreaEnum,
+} from "@/shared/types/enums";
import { DaoIconProps } from "@/shared/components/icons/types";
import { MetricTypesEnum } from "../types/enums/metric-type";
@@ -29,11 +33,15 @@ export type GovernanceImplementation = {
};
export type GovernanceImplementationField = {
- value: string;
- description: string;
riskLevel: RiskLevel;
- requirements?: string[];
- riskExplanation?: string;
+ description: string;
+
+ requirements?: string[]; // Remove this when update Risk Analysis and Stages to not rely on it
+
+ currentSetting?: string;
+ impact?: string;
+ recommendedSetting?: string;
+ nextStep?: string;
};
// Base DAO information
@@ -108,6 +116,15 @@ export interface AttackProfitabilityConfig {
percentage: number;
};
}
+
+export type DefenseAreaDescription = {
+ description: string;
+};
+
+export type AttackExposureConfig = {
+ defenseAreas?: Partial>;
+};
+
export interface GovernanceImplementationConfig extends GovernanceImplementation {}
// Complete DAO configuration structure
@@ -115,6 +132,7 @@ export interface DaoConfiguration extends BaseInfo {
daoOverview: DaoOverviewConfig;
attackProfitability?: AttackProfitabilityConfig;
governanceImplementation?: GovernanceImplementationConfig;
+ attackExposure?: AttackExposureConfig;
resilienceStages?: boolean;
tokenDistribution?: boolean;
dataTables?: boolean;
diff --git a/apps/dashboard/shared/dao-config/uni.ts b/apps/dashboard/shared/dao-config/uni.ts
index 4b6b1f99a..f2fbda8a8 100644
--- a/apps/dashboard/shared/dao-config/uni.ts
+++ b/apps/dashboard/shared/dao-config/uni.ts
@@ -6,6 +6,8 @@ import { UniswapIcon } from "@/shared/components/icons";
import { mainnet } from "viem/chains";
import { QUORUM_CALCULATION_TYPES } from "@/shared/constants/labels";
import { MainnetIcon } from "@/shared/components/icons/MainnetIcon";
+import { RECOMMENDED_SETTINGS } from "@/shared/constants/recommended-settings";
+import { RiskAreaEnum } from "@/shared/types/enums/RiskArea";
export const UNI: DaoConfiguration = {
name: "Uniswap",
@@ -44,104 +46,190 @@ export const UNI: DaoConfiguration = {
// Fields are sorted alphabetically by GovernanceImplementationEnum for readability
fields: {
[GovernanceImplementationEnum.AUDITED_CONTRACTS]: {
- value: "Yes",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.AUDITED_CONTRACTS
].description,
+ currentSetting:
+ "The Uniswap DAO contracts have been audited, and the audit is publicly available.",
+ impact:
+ "With its governance contracts audited, the risk of vulnerabilities in them is minimized.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.AUDITED_CONTRACTS],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.INTERFACE_HIJACK]: {
- value: "No",
riskLevel: RiskLevel.MEDIUM,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.INTERFACE_HIJACK
].description,
+ currentSetting:
+ "The Uniswap governance interface on tally has a secure HTTPS connection and is signed with DNSSEC.",
+ impact:
+ "The voting interface used has certificates to guarantee its source of content. It is still vulnerable to malicious/mistakenly pushed code by the third party provider.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.INTERFACE_HIJACK],
+ nextStep:
+ "The DAO should host an immutable interface for voting, registering it to an ENS like vote.uniswap.eth and made available through .limo, .link or similar.",
requirements: [
"For maximum security, the DAO should have its frontend reviewed by the DAO or audit and then made verifiably immutable",
"A solution could look like a frontend made available on IPFS through eth.limo, with their code hashed and put on chain by the DAO, then verified for subresource integrity",
"The governance interface used (Tally) has the standard protections to prevent external tampering with the frontend accessed",
"The platform is still exposed to any malicious or compromised actors inside the interface provider team",
],
- riskExplanation: `Although protected from spoofing or hijacking, the service used for voting could still be internally compromised.\n
- A change in the voting interface could be used to manipulate the results of the vote, hiding malicious txns, or even changing selection of votes.`,
},
[GovernanceImplementationEnum.ATTACK_PROFITABILITY]: {
- value: "<10k USD",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.ATTACK_PROFITABILITY
].description,
+ currentSetting:
+ "The extractable value of the Uniswap DAO is less than $10K, since its treasury consists only of governance tokens and has no liquid assets.",
+ impact:
+ "The incentives to capture a DAO with a high delegated cap and no liquid treasury beyond its own token are lower than in other DAOs.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[
+ GovernanceImplementationEnum.ATTACK_PROFITABILITY
+ ],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.PROPOSAL_FLASHLOAN_PROTECTION]: {
- value: "Yes",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.PROPOSAL_FLASHLOAN_PROTECTION
].description,
+ currentSetting:
+ "It protects the DAO from a flash loan aimed at reaching the Proposal Threshold and submitting a proposal, by taking a snapshot of the governance power from delegates/holders one block before the proposal submission.",
+ impact:
+ "It is not possible to use a flash loan to reach the amount required to submit a proposal.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[
+ GovernanceImplementationEnum.PROPOSAL_FLASHLOAN_PROTECTION
+ ],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.PROPOSAL_THRESHOLD]: {
- value: "1M UNI",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.PROPOSAL_THRESHOLD
].description,
+ currentSetting:
+ "The Proposal Threshold is set to 1M $UNI (0,1% Total Supply)",
+ impact:
+ "The DAO has a sufficiently high proposal threshold to avoid spam proposals and discourage attacks.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.PROPOSAL_THRESHOLD],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
- [GovernanceImplementationEnum.PROPOSAL_THRESHOLD_CANCEL]: {
- value: "Yes",
+ [GovernanceImplementationEnum.PROPOSER_BALANCE_CANCEL]: {
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
- GovernanceImplementationEnum.PROPOSAL_THRESHOLD_CANCEL
+ GovernanceImplementationEnum.PROPOSER_BALANCE_CANCEL
].description,
+ currentSetting:
+ "Uniswap has a cancellation mechanism: if the proposer sells their tokens and their balance falls below the Proposal Threshold, the proposal is automatically canceled.",
+ impact:
+ "If the proposer sells their tokens and their balance falls below the Proposal Threshold, the proposal is can be cancelled by any address.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[
+ GovernanceImplementationEnum.PROPOSER_BALANCE_CANCEL
+ ],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
- [GovernanceImplementationEnum.PROPOSER_BALANCE_CANCEL]: {
- value: "Yes",
- riskLevel: RiskLevel.LOW,
+ [GovernanceImplementationEnum.SECURITY_COUNCIL]: {
+ riskLevel: RiskLevel.MEDIUM,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
- GovernanceImplementationEnum.PROPOSER_BALANCE_CANCEL
+ GovernanceImplementationEnum.SECURITY_COUNCIL
].description,
+ currentSetting: "The Uniswap DAO has no Security Council.",
+ impact:
+ "Without a Security Council, there is no protection mechanism against malicious proposals that get approved.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.SECURITY_COUNCIL],
+ nextStep: "-",
},
[GovernanceImplementationEnum.SPAM_RESISTANCE]: {
- value: "Yes",
- riskLevel: RiskLevel.LOW,
+ riskLevel: RiskLevel.HIGH,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.SPAM_RESISTANCE
].description,
+ currentSetting:
+ "There is a limit of one live/pending proposal per address that any address can submit to the DAO.",
+ impact:
+ "A single address can only have one live proposal at the time, effectively protecting governance from a spam attack.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.SPAM_RESISTANCE],
+ nextStep:
+ "It is necessary to limit the number of proposals that can be submitted by a single address.",
},
[GovernanceImplementationEnum.TIMELOCK_ADMIN]: {
- value: "Only Governor",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.TIMELOCK_ADMIN
].description,
+ currentSetting: "Governor is the only Admin role on timelock.",
+ impact:
+ "Since the Governor is the only administrator of the Timelock, only the DAO can control it - decentralizing its governance.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.TIMELOCK_ADMIN],
+ nextStep: "The parameter is in its lowest-risk condition.",
requirements: [
"The timelock admin can control execution, canceling, upgrades or critical parameter changes; if this power sits outside audited, DAO-approved contracts, attackers or insiders can sidestep on-chain voting.",
"Admin rights should rest only with DAO governance plus contracts it explicitly approves after a public audit.",
],
},
[GovernanceImplementationEnum.TIMELOCK_DELAY]: {
- value: "2 days",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.TIMELOCK_DELAY
].description,
+ currentSetting:
+ "The Timelock execution delay for an approved proposal is 2 days.",
+ impact:
+ "There is a protected delay between proposal approval and execution.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.TIMELOCK_DELAY],
+ nextStep: "The parameter is in its lowest-risk condition.",
+ },
+ [GovernanceImplementationEnum.VETO_STRATEGY]: {
+ riskLevel: RiskLevel.MEDIUM,
+ description:
+ GOVERNANCE_IMPLEMENTATION_CONSTANTS[
+ GovernanceImplementationEnum.VETO_STRATEGY
+ ].description,
+ currentSetting:
+ "Uniswap don't have a cancel function activated or a Security Council to stop malicious proposals. ",
+ impact:
+ "Without a veto strategy, a malicious proposal that gets approved will be executed.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VETO_STRATEGY],
+ nextStep:
+ "The DAO has no need for a veto strategy at this moment, given the level of economic security it has.",
},
[GovernanceImplementationEnum.VOTE_MUTABILITY]: {
- value: "No",
riskLevel: RiskLevel.MEDIUM,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VOTE_MUTABILITY
].description,
+ currentSetting:
+ "The DAO does not allow changing votes once they have been cast.",
+ impact:
+ "Governance participants cannot change their votes after casting them. In the event of an interface hijack on the voting platform to support the attack, voters cannot revert their vote.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VOTE_MUTABILITY],
+ nextStep:
+ "Allow voters to change their vote until the Voting Period ends.",
requirements: [
"If ballots can’t be changed, a late‑discovered UI exploit or code bug can trap delegates in a now‑malicious vote, weakening defenses.",
"Currently, votes become immutable once cast (Medium Risk).",
@@ -149,12 +237,17 @@ export const UNI: DaoConfiguration = {
],
},
[GovernanceImplementationEnum.VOTING_DELAY]: {
- value: "44h",
riskLevel: RiskLevel.MEDIUM,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VOTING_DELAY
].description,
+ currentSetting: "The Voting Delay is set to 1 day and 19 hours",
+ impact:
+ "Given the current Voting Delay, the DAO has sufficient time to coordinate stakeholders and wallets before the snapshot (that counts votes) occurs.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VOTING_DELAY],
+ nextStep: "The parameter is in its lowest-risk condition.",
requirements: [
"A short window between proposal submission and the voting snapshot lets attackers rush malicious items through before delegates mobilize.",
"Currently, the delay is 44 h (Medium Risk).",
@@ -162,20 +255,33 @@ export const UNI: DaoConfiguration = {
],
},
[GovernanceImplementationEnum.VOTING_FLASHLOAN_PROTECTION]: {
- value: "Yes",
riskLevel: RiskLevel.LOW,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VOTING_FLASHLOAN_PROTECTION
].description,
+ currentSetting:
+ "It protects the DAO from a flash loan aimed to increase their voting power, by taking a snapshot of the governance power from delegates/holders one block before the Voting Period starts",
+ impact:
+ "It is not possible to use a flash loan to increase voting power and approve a proposal.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[
+ GovernanceImplementationEnum.VOTING_FLASHLOAN_PROTECTION
+ ],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
[GovernanceImplementationEnum.VOTING_PERIOD]: {
- value: "5d 6h",
riskLevel: RiskLevel.MEDIUM,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VOTING_PERIOD
].description,
+ currentSetting: "The Voting Period is set to 5 day and 6 hours",
+ impact:
+ "The current Voting Period is sufficient for governance participants to cast their votes.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VOTING_PERIOD],
+ nextStep: "The parameter is in its lowest-risk condition.",
requirements: [
"A voting window under seven days risks excluding weekend or time‑zoned delegates, lowering turnout and quorum.",
"Currently, voting lasts 5 d 6 h (Medium Risk).",
@@ -183,12 +289,18 @@ export const UNI: DaoConfiguration = {
],
},
[GovernanceImplementationEnum.VOTING_SUBSIDY]: {
- value: "Yes",
- riskLevel: RiskLevel.LOW,
+ riskLevel: RiskLevel.MEDIUM,
description:
GOVERNANCE_IMPLEMENTATION_CONSTANTS[
GovernanceImplementationEnum.VOTING_SUBSIDY
].description,
+ currentSetting:
+ "There is no subsidy to help voters participate in governance voting.",
+ impact:
+ "Without subsidies, voters incur costs to participate in governance. During periods of high gas fees, participation may decrease, making the DAO easier to attack.",
+ recommendedSetting:
+ RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VOTING_SUBSIDY],
+ nextStep: "The parameter is in its lowest-risk condition.",
},
},
},
@@ -196,7 +308,31 @@ export const UNI: DaoConfiguration = {
riskLevel: RiskLevel.LOW,
supportsLiquidTreasuryCall: true,
},
- riskAnalysis: true,
+ attackExposure: {
+ defenseAreas: {
+ [RiskAreaEnum.SPAM_RESISTANCE]: {
+ description:
+ "Voting period is below the ideal length, moderately reducing resistance to sustained proposal spam.",
+ },
+ [RiskAreaEnum.ECONOMIC_SECURITY]: {
+ description: "All metrics in this defense are currently in low risk.",
+ },
+ [RiskAreaEnum.SAFEGUARDS]: {
+ description: "All metrics in this defense are currently in low risk.",
+ },
+ [RiskAreaEnum.CONTRACT_SAFETY]: {
+ description: "All metrics in this defense are currently in low risk.",
+ },
+ [RiskAreaEnum.RESPONSE_TIME]: {
+ description:
+ "Response time is partially limited by shorter-than-ideal voting delay and voting period, reducing the window for coordinated reaction and review.",
+ },
+ [RiskAreaEnum.GOV_FRONTEND_RESILIENCE]: {
+ description:
+ "Interface protections are present but not fully hardened, and immutable votes limit recovery in the event of front-end compromise, resulting in moderate governance interface risk.",
+ },
+ },
+ },
tokenDistribution: true,
resilienceStages: true,
dataTables: true,
diff --git a/apps/dashboard/shared/types/enums/GovernanceImplementation.ts b/apps/dashboard/shared/types/enums/GovernanceImplementation.ts
index 8fd294f99..fa39b82cb 100644
--- a/apps/dashboard/shared/types/enums/GovernanceImplementation.ts
+++ b/apps/dashboard/shared/types/enums/GovernanceImplementation.ts
@@ -9,7 +9,6 @@ export enum GovernanceImplementationEnum {
PROPOSAL_FLASHLOAN_PROTECTION = "Proposal Flashloan Protection",
PROPOSAL_THRESHOLD = "Proposal Threshold",
PROPOSER_BALANCE_CANCEL = "Proposer Balance Cancel",
- PROPOSAL_THRESHOLD_CANCEL = "Proposal Threshold Cancel",
SECURITY_COUNCIL = "Security Council",
SPAM_RESISTANCE = "Spam Resistance",
TIMELOCK_ADMIN = "Timelock Admin",
diff --git a/apps/dashboard/shared/types/enums/RiskArea.ts b/apps/dashboard/shared/types/enums/RiskArea.ts
index 019fb215e..9b135d743 100644
--- a/apps/dashboard/shared/types/enums/RiskArea.ts
+++ b/apps/dashboard/shared/types/enums/RiskArea.ts
@@ -1,11 +1,11 @@
/**
- * Enum representing all risk areas that can be analyzed for a DAO
+ * Enum representing all risk areas (defense areas) that can be analyzed for a DAO
*/
export enum RiskAreaEnum {
- SPAM_VULNERABLE = "SPAM VULNERABLE",
- ATTACK_PROFITABILITY = "ATTACK PROFITABILITY",
+ SPAM_RESISTANCE = "SPAM RESISTANCE",
+ ECONOMIC_SECURITY = "ECONOMIC SECURITY",
SAFEGUARDS = "SAFEGUARDS",
- HACKABLE = "HACKABLE",
+ CONTRACT_SAFETY = "CONTRACT SAFETY",
RESPONSE_TIME = "RESPONSE TIME",
- GOV_FRONTEND_VULNERABILITY = "GOV FRONT-END VULNERABILITY",
+ GOV_FRONTEND_RESILIENCE = "GOV FRONT-END RESILIENCE",
}
diff --git a/apps/dashboard/templates/DaoTemplate.tsx b/apps/dashboard/templates/DaoTemplate.tsx
index 0e7d020bc..2b379e53b 100644
--- a/apps/dashboard/templates/DaoTemplate.tsx
+++ b/apps/dashboard/templates/DaoTemplate.tsx
@@ -5,7 +5,6 @@ import { DaoIdEnum } from "@/shared/types/daos";
import daoConfigByDaoId from "@/shared/dao-config";
import { AttackProfitabilitySection } from "@/features/attack-profitability";
import { RiskAnalysisSection } from "@/features/risk-analysis";
-import { GovernanceImplementationSection } from "@/features/governance-implementation";
import { ResilienceStagesSection } from "@/features/resilience-stages";
import { DaoOverviewSection } from "@/features/dao-overview";
import { TokenDistributionSection } from "@/features/token-distribution";
@@ -63,9 +62,8 @@ export const DaoTemplate = () => {
attackProfitability={daoConstants.attackProfitability}
/>
)}
- {daoConstants.riskAnalysis && }
- {daoConstants.governanceImplementation && (
-
+ {daoConstants.attackExposure && (
+
)}
{daoConstants.resilienceStages && (
diff --git a/apps/dashboard/widgets/HeaderDAOSidebar.tsx b/apps/dashboard/widgets/HeaderDAOSidebar.tsx
index 4c330fba8..38dd8f5cd 100644
--- a/apps/dashboard/widgets/HeaderDAOSidebar.tsx
+++ b/apps/dashboard/widgets/HeaderDAOSidebar.tsx
@@ -7,7 +7,7 @@ import {
HeaderDAOSidebarDropdown,
ButtonHeaderSidebar,
} from "@/shared/components";
-import { BarChart, Gauge, Landmark, UserCheck } from "lucide-react";
+import { BarChart, Bomb, Landmark, UserCheck } from "lucide-react";
import daoConfigByDaoId from "@/shared/dao-config";
import { ArrowRightLeft, PieChart } from "lucide-react";
import { Crosshair2Icon } from "@radix-ui/react-icons";
@@ -59,12 +59,12 @@ export const HeaderDAOSidebar = () => {
isCollapsed={isCollapsed}
/>
)}
- {daoConfig.riskAnalysis && (
+ {daoConfig.attackExposure && (
)}
diff --git a/apps/dashboard/widgets/HeaderNavMobile.tsx b/apps/dashboard/widgets/HeaderNavMobile.tsx
index 4d035c0ba..a7eb4735b 100644
--- a/apps/dashboard/widgets/HeaderNavMobile.tsx
+++ b/apps/dashboard/widgets/HeaderNavMobile.tsx
@@ -26,9 +26,9 @@ export const HeaderNavMobile = () => {
enabled: !!daoConfig.attackProfitability,
},
{
- page: PAGES_CONSTANTS.riskAnalysis.page,
- title: PAGES_CONSTANTS.riskAnalysis.title,
- enabled: !!daoConfig.riskAnalysis,
+ page: PAGES_CONSTANTS.attackExposure.page,
+ title: PAGES_CONSTANTS.attackExposure.title,
+ enabled: !!daoConfig.attackExposure,
},
{
page: PAGES_CONSTANTS.resilienceStages.page,