diff --git a/apps/api-gateway/schema.graphql b/apps/api-gateway/schema.graphql index 9a07adef5..803badce7 100644 --- a/apps/api-gateway/schema.graphql +++ b/apps/api-gateway/schema.graphql @@ -11,7 +11,7 @@ directive @httpOperation(subgraph: String, path: String, operationSpecificHeader directive @transport(subgraph: String, kind: String, location: String, headers: [[String]], queryStringOptions: ObjMap, queryParams: [[String]]) repeatable on SCHEMA type Query { - """Get property data for a specific token""" + "\n>**Method**: `GET`\n>**Base URL**: `https://zk-api-dev.up.railway.app`\n>**Path**: `/token`\nGet property data for a specific token\n" token(currency: queryInput_token_currency = usd): token_200_response tokens(where: tokenFilter, orderBy: String, orderDirection: String, before: String, after: String, limit: Int): tokenPage! account(id: String!): account @@ -38,69 +38,61 @@ type Query { tokenPrices(where: tokenPriceFilter, orderBy: String, orderDirection: String, before: String, after: String, limit: Int): tokenPricePage! _meta: Meta - """Get historical market data for a specific token""" + "\n>**Method**: `GET`\n>**Base URL**: `https://zk-api-dev.up.railway.app`\n>**Path**: `/token/historical-data`\nGet historical market data for a specific token\n" historicalTokenData(skip: NonNegativeInt, limit: Float = 365): [query_historicalTokenData_items] - """Compare total supply between periods""" + "\n>**Method**: `GET`\n>**Base URL**: `https://zk-api-dev.up.railway.app`\n>**Path**: `/total-supply/compare`\nCompare total supply between periods\n" compareTotalSupply(days: queryInput_compareTotalSupply_days = _90d): compareTotalSupply_200_response - """Compare delegated supply between periods""" + "\n>**Method**: `GET`\n>**Base URL**: `https://zk-api-dev.up.railway.app`\n>**Path**: `/delegated-supply/compare`\nCompare delegated supply between periods\n" compareDelegatedSupply(days: queryInput_compareDelegatedSupply_days = _90d): compareDelegatedSupply_200_response - """Compare circulating supply between periods""" + "\n>**Method**: `GET`\n>**Base URL**: `https://zk-api-dev.up.railway.app`\n>**Path**: `/circulating-supply/compare`\nCompare circulating supply between periods\n" compareCirculatingSupply(days: queryInput_compareCirculatingSupply_days = _90d): compareCirculatingSupply_200_response - """Compare treasury between periods""" + "\n>**Method**: `GET`\n>**Base URL**: `https://zk-api-dev.up.railway.app`\n>**Path**: `/treasury/compare`\nCompare treasury between periods\n" compareTreasury(days: queryInput_compareTreasury_days = _90d): compareTreasury_200_response - """Compare cex supply between periods""" + "\n>**Method**: `GET`\n>**Base URL**: `https://zk-api-dev.up.railway.app`\n>**Path**: `/cex-supply/compare`\nCompare cex supply between periods\n" compareCexSupply(days: queryInput_compareCexSupply_days = _90d): compareCexSupply_200_response - """Compare dex supply between periods""" + "\n>**Method**: `GET`\n>**Base URL**: `https://zk-api-dev.up.railway.app`\n>**Path**: `/dex-supply/compare`\nCompare dex supply between periods\n" compareDexSupply(days: queryInput_compareDexSupply_days = _90d): compareDexSupply_200_response - """Compare lending supply between periods""" + "\n>**Method**: `GET`\n>**Base URL**: `https://zk-api-dev.up.railway.app`\n>**Path**: `/lending-supply/compare`\nCompare lending supply between periods\n" compareLendingSupply(days: queryInput_compareLendingSupply_days = _90d): compareLendingSupply_200_response - """Get active token supply for DAO""" + "\n>**Method**: `GET`\n>**Base URL**: `https://zk-api-dev.up.railway.app`\n>**Path**: `/active-supply/compare`\nGet active token supply for DAO\n" compareActiveSupply(days: queryInput_compareActiveSupply_days = _90d): compareActiveSupply_200_response - """Compare number of proposals between time periods""" + "\n>**Method**: `GET`\n>**Base URL**: `https://zk-api-dev.up.railway.app`\n>**Path**: `/proposals/compare`\nCompare number of proposals between time periods\n" compareProposals(days: queryInput_compareProposals_days = _90d): compareProposals_200_response - """Compare number of votes between time periods""" + "\n>**Method**: `GET`\n>**Base URL**: `https://zk-api-dev.up.railway.app`\n>**Path**: `/votes/compare`\nCompare number of votes between time periods\n" compareVotes(days: queryInput_compareVotes_days = _90d): compareVotes_200_response - """Compare average turnout between time periods""" + "\n>**Method**: `GET`\n>**Base URL**: `https://zk-api-dev.up.railway.app`\n>**Path**: `/average-turnout/compare`\nCompare average turnout between time periods\n" compareAverageTurnout(days: queryInput_compareAverageTurnout_days = _90d): compareAverageTurnout_200_response - """ - Returns proposal activity data including voting history, win rates, and detailed proposal information for the specified delegate within the given time window - """ + "\n>**Method**: `GET`\n>**Base URL**: `https://zk-api-dev.up.railway.app`\n>**Path**: `/proposals-activity`\nReturns proposal activity data including voting history, win rates, and detailed proposal information for the specified delegate within the given time window\n" proposalsActivity(address: String!, fromDate: NonNegativeInt, skip: NonNegativeInt, limit: PositiveInt = 10, orderBy: queryInput_proposalsActivity_orderBy = timestamp, orderDirection: queryInput_proposalsActivity_orderDirection = desc, userVoteFilter: queryInput_proposalsActivity_userVoteFilter): proposalsActivity_200_response - """Returns a list of proposal""" + "\n>**Method**: `GET`\n>**Base URL**: `https://zk-api-dev.up.railway.app`\n>**Path**: `/proposals`\nReturns a list of proposal\n" proposals(skip: NonNegativeInt, limit: PositiveInt = 10, orderDirection: queryInput_proposals_orderDirection = desc, status: JSON, fromDate: Float, fromEndDate: Float): proposals_200_response - """Returns a single proposal by its ID""" + "\n>**Method**: `GET`\n>**Base URL**: `https://zk-api-dev.up.railway.app`\n>**Path**: `/proposals/{args.id}`\nReturns a single proposal by its ID\n" proposal(id: String!): proposal_200_response - """Returns the active delegates that did not vote on a given proposal""" + "\n>**Method**: `GET`\n>**Base URL**: `https://zk-api-dev.up.railway.app`\n>**Path**: `/proposals/{args.id}/non-voters`\nReturns the active delegates that did not vote on a given proposal\n" proposalNonVoters(id: String!, skip: NonNegativeInt, limit: PositiveInt = 10, orderDirection: queryInput_proposalNonVoters_orderDirection = desc, addresses: JSON): proposalNonVoters_200_response - """ - Fetch historical token balances for multiple addresses at a specific time period using multicall - """ + "\n>**Method**: `GET`\n>**Base URL**: `https://zk-api-dev.up.railway.app`\n>**Path**: `/historical-balances`\nFetch historical token balances for multiple addresses at a specific time period using multicall\n" historicalBalances(addresses: JSON!, days: queryInput_historicalBalances_days = _7d): [query_historicalBalances_items] - """ - Fetch historical voting power for multiple addresses at a specific time period using multicall - """ + "\n>**Method**: `GET`\n>**Base URL**: `https://zk-api-dev.up.railway.app`\n>**Path**: `/historical-voting-power`\nFetch historical voting power for multiple addresses at a specific time period using multicall\n" historicalVotingPower(addresses: JSON!, days: queryInput_historicalVotingPower_days = _7d, fromDate: Float): [query_historicalVotingPower_items] - """ - Get transactions with their associated transfers and delegations, with optional filtering and sorting - """ + "\n>**Method**: `GET`\n>**Base URL**: `https://zk-api-dev.up.railway.app`\n>**Path**: `/transactions`\nGet transactions with their associated transfers and delegations, with optional filtering and sorting\n" transactions( limit: PositiveInt = 50 offset: NonNegativeInt @@ -122,23 +114,19 @@ type Query { includes: JSON ): transactions_200_response - """Get the last update time""" + "\n>**Method**: `GET`\n>**Base URL**: `https://zk-api-dev.up.railway.app`\n>**Path**: `/last-update`\nGet the last update time\n" lastUpdate(chart: queryInput_lastUpdate_chart!): lastUpdate_200_response - """Get delegation percentage day buckets with forward-fill""" + "\n>**Method**: `GET`\n>**Base URL**: `https://zk-api-dev.up.railway.app`\n>**Path**: `/delegation-percentage`\nGet delegation percentage day buckets with forward-fill\n" delegationPercentageByDay(startDate: String, endDate: String, orderDirection: queryInput_delegationPercentageByDay_orderDirection = asc, limit: NonNegativeInt = 365, after: String, before: String): delegationPercentageByDay_200_response - """Returns a list of voting power changes""" + "\n>**Method**: `GET`\n>**Base URL**: `https://zk-api-dev.up.railway.app`\n>**Path**: `/voting-powers`\nReturns a list of voting power changes\n" votingPowers(account: String!, skip: NonNegativeInt, limit: PositiveInt = 10, orderBy: queryInput_votingPowers_orderBy = timestamp, orderDirection: queryInput_votingPowers_orderDirection = desc, minDelta: String, maxDelta: String): votingPowers_200_response - """ - Returns a mapping of the biggest changes to voting power associated by delegate address - """ + "\n>**Method**: `GET`\n>**Base URL**: `https://zk-api-dev.up.railway.app`\n>**Path**: `/voting-power/variations`\nReturns a mapping of the biggest changes to voting power associated by delegate address\n" votingPowerVariations(days: queryInput_votingPowerVariations_days = _90d, limit: PositiveInt = 20, skip: NonNegativeInt, orderDirection: queryInput_votingPowerVariations_orderDirection = desc): votingPowerVariations_200_response - """ - Returns a mapping of the biggest variations to account balances associated by account address - """ + "\n>**Method**: `GET`\n>**Base URL**: `https://zk-api-dev.up.railway.app`\n>**Path**: `/account-balance/variations`\nReturns a mapping of the biggest variations to account balances associated by account address\n" accountBalanceVariations(days: queryInput_accountBalanceVariations_days = _90d, limit: PositiveInt = 20, skip: NonNegativeInt, orderDirection: queryInput_accountBalanceVariations_orderDirection = desc): accountBalanceVariations_200_response """ diff --git a/apps/dashboard/app/[daoId]/(main)/attack-profitability/page.tsx b/apps/dashboard/app/[daoId]/(main)/attack-profitability/page.tsx index ab37244b5..fb145a9b2 100644 --- a/apps/dashboard/app/[daoId]/(main)/attack-profitability/page.tsx +++ b/apps/dashboard/app/[daoId]/(main)/attack-profitability/page.tsx @@ -30,6 +30,7 @@ export async function generateMetadata(props: Props): Promise { [DaoIdEnum.NOUNS]: `${baseUrl}/opengraph-images/nouns.png`, [DaoIdEnum.OBOL]: `${baseUrl}/opengraph-images/obol.png`, [DaoIdEnum.COMP]: `${baseUrl}/opengraph-images/comp.png`, + [DaoIdEnum.ZK]: `${baseUrl}/opengraph-images/zk.png`, }; const imageUrl = diff --git a/apps/dashboard/app/[daoId]/(main)/holders-and-delegates/page.tsx b/apps/dashboard/app/[daoId]/(main)/holders-and-delegates/page.tsx index 76701e5f2..15bf90f34 100644 --- a/apps/dashboard/app/[daoId]/(main)/holders-and-delegates/page.tsx +++ b/apps/dashboard/app/[daoId]/(main)/holders-and-delegates/page.tsx @@ -26,6 +26,7 @@ export async function generateMetadata(props: Props): Promise { [DaoIdEnum.NOUNS]: `${baseUrl}/opengraph-images/nouns.png`, [DaoIdEnum.OBOL]: `${baseUrl}/opengraph-images/obol.png`, [DaoIdEnum.COMP]: `${baseUrl}/opengraph-images/comp.png`, + [DaoIdEnum.ZK]: `${baseUrl}/opengraph-images/zk.png`, }; const imageUrl = diff --git a/apps/dashboard/app/[daoId]/(main)/resilience-stages/page.tsx b/apps/dashboard/app/[daoId]/(main)/resilience-stages/page.tsx index 190f7f1e9..b949106cf 100644 --- a/apps/dashboard/app/[daoId]/(main)/resilience-stages/page.tsx +++ b/apps/dashboard/app/[daoId]/(main)/resilience-stages/page.tsx @@ -26,6 +26,7 @@ export async function generateMetadata(props: Props): Promise { [DaoIdEnum.NOUNS]: `${baseUrl}/opengraph-images/nouns.png`, [DaoIdEnum.OBOL]: `${baseUrl}/opengraph-images/obol.png`, [DaoIdEnum.COMP]: `${baseUrl}/opengraph-images/comp.png`, + [DaoIdEnum.ZK]: `${baseUrl}/opengraph-images/zk.png`, }; const imageUrl = diff --git a/apps/dashboard/app/[daoId]/(main)/risk-analysis/page.tsx b/apps/dashboard/app/[daoId]/(main)/risk-analysis/page.tsx index 948d7b8bc..1b137a147 100644 --- a/apps/dashboard/app/[daoId]/(main)/risk-analysis/page.tsx +++ b/apps/dashboard/app/[daoId]/(main)/risk-analysis/page.tsx @@ -37,6 +37,7 @@ export async function generateMetadata(props: Props): Promise { [DaoIdEnum.NOUNS]: `${baseUrl}/opengraph-images/nouns.png`, [DaoIdEnum.OBOL]: `${baseUrl}/opengraph-images/obol.png`, [DaoIdEnum.COMP]: `${baseUrl}/opengraph-images/comp.png`, + [DaoIdEnum.ZK]: `${baseUrl}/opengraph-images/zk.png`, }; const imageUrl = diff --git a/apps/dashboard/app/[daoId]/(main)/token-distribution/page.tsx b/apps/dashboard/app/[daoId]/(main)/token-distribution/page.tsx index 63ff83ad6..eee1aec98 100644 --- a/apps/dashboard/app/[daoId]/(main)/token-distribution/page.tsx +++ b/apps/dashboard/app/[daoId]/(main)/token-distribution/page.tsx @@ -30,6 +30,7 @@ export async function generateMetadata(props: Props): Promise { [DaoIdEnum.NOUNS]: `${baseUrl}/opengraph-images/nouns.png`, [DaoIdEnum.OBOL]: `${baseUrl}/opengraph-images/obol.png`, [DaoIdEnum.COMP]: `${baseUrl}/opengraph-images/comp.png`, + [DaoIdEnum.ZK]: `${baseUrl}/opengraph-images/zk.png`, }; const imageUrl = diff --git a/apps/dashboard/app/[daoId]/(secondary)/governance/page.tsx b/apps/dashboard/app/[daoId]/(secondary)/governance/page.tsx index 15f4bb714..2d88a54c7 100644 --- a/apps/dashboard/app/[daoId]/(secondary)/governance/page.tsx +++ b/apps/dashboard/app/[daoId]/(secondary)/governance/page.tsx @@ -30,6 +30,7 @@ export async function generateMetadata(props: Props): Promise { [DaoIdEnum.SCR]: `${baseUrl}/opengraph-images/scr.png`, [DaoIdEnum.OBOL]: `${baseUrl}/opengraph-images/obol.png`, [DaoIdEnum.COMP]: `${baseUrl}/opengraph-images/comp.png`, + [DaoIdEnum.ZK]: `${baseUrl}/opengraph-images/zk.png`, }; const ogTitle = `Anticapture - ${daoId} DAO`; diff --git a/apps/dashboard/app/[daoId]/(secondary)/governance/proposal/[proposalId]/page.tsx b/apps/dashboard/app/[daoId]/(secondary)/governance/proposal/[proposalId]/page.tsx index 8ed158ee1..8b18f9128 100644 --- a/apps/dashboard/app/[daoId]/(secondary)/governance/proposal/[proposalId]/page.tsx +++ b/apps/dashboard/app/[daoId]/(secondary)/governance/proposal/[proposalId]/page.tsx @@ -30,6 +30,7 @@ export async function generateMetadata(props: Props): Promise { [DaoIdEnum.SCR]: `${baseUrl}/opengraph-images/scr.png`, [DaoIdEnum.OBOL]: `${baseUrl}/opengraph-images/obol.png`, [DaoIdEnum.COMP]: `${baseUrl}/opengraph-images/comp.png`, + [DaoIdEnum.ZK]: `${baseUrl}/opengraph-images/zk.png`, }; const imageUrl = diff --git a/apps/dashboard/features/panel/components/PanelTable.tsx b/apps/dashboard/features/panel/components/PanelTable.tsx index 27ed0a89e..373161e68 100644 --- a/apps/dashboard/features/panel/components/PanelTable.tsx +++ b/apps/dashboard/features/panel/components/PanelTable.tsx @@ -51,10 +51,12 @@ export const PanelTable = ({ currency }: PanelTableProps) => { const quorumGapValues = useRef>({}); // Create initial data - const data = Object.values(DaoIdEnum).map((daoId, index) => ({ - id: index, - dao: daoId, - })); + const data = Object.values(DaoIdEnum) // TODO: un-hide ZK once released + .filter((daoIdValue, _) => daoIdValue !== DaoIdEnum.ZK) + .map((daoId, index) => ({ + id: index, + dao: daoId, + })); // Liquid Treasury Cell // const LiquidTreasuryCell = ({ diff --git a/apps/dashboard/public/opengraph-images/zk.png b/apps/dashboard/public/opengraph-images/zk.png new file mode 100644 index 000000000..94fc18ca0 Binary files /dev/null and b/apps/dashboard/public/opengraph-images/zk.png differ diff --git a/apps/dashboard/shared/components/dropdowns/HeaderDAOSidebarDropdown.tsx b/apps/dashboard/shared/components/dropdowns/HeaderDAOSidebarDropdown.tsx index 6ba41acd1..685d2d780 100644 --- a/apps/dashboard/shared/components/dropdowns/HeaderDAOSidebarDropdown.tsx +++ b/apps/dashboard/shared/components/dropdowns/HeaderDAOSidebarDropdown.tsx @@ -52,8 +52,9 @@ export const HeaderDAOSidebarDropdown = () => { // stable, single-build dropdown items (imports are static) const dropdownItemsRef = useRef(null); if (!dropdownItemsRef.current) { - dropdownItemsRef.current = Object.values(DaoIdEnum).map( - (daoIdValue, index) => ({ + dropdownItemsRef.current = Object.values(DaoIdEnum) + .filter((daoIdValue, _) => daoIdValue !== DaoIdEnum.ZK) // TODO: un-hide ZK once released + .map((daoIdValue, index) => ({ id: index, label: daoConfigByDaoId[daoIdValue].name, icon: ( @@ -65,8 +66,7 @@ export const HeaderDAOSidebarDropdown = () => { ), href: `/${daoIdValue.toLowerCase()}`, name: daoIdValue, - }), - ); + })); } const dropdownItems = dropdownItemsRef.current!; diff --git a/apps/dashboard/shared/components/icons/ZKIcon.tsx b/apps/dashboard/shared/components/icons/ZKIcon.tsx new file mode 100644 index 000000000..122c23899 --- /dev/null +++ b/apps/dashboard/shared/components/icons/ZKIcon.tsx @@ -0,0 +1,27 @@ +import { DaoIconProps } from "@/shared/components/icons/types"; + +export const ZKIcon = ({ ...props }: DaoIconProps) => { + return ( + + + + + ); +}; diff --git a/apps/dashboard/shared/components/icons/index.ts b/apps/dashboard/shared/components/icons/index.ts index e1e184bde..bf22de64c 100644 --- a/apps/dashboard/shared/components/icons/index.ts +++ b/apps/dashboard/shared/components/icons/index.ts @@ -13,6 +13,7 @@ export * from "@/shared/components/icons/GitcoinIcon"; export * from "@/shared/components/icons/ScrollIcon"; export * from "@/shared/components/icons/CompoundIcon"; export * from "@/shared/components/icons/ObolIcon"; +export * from "@/shared/components/icons/ZKIcon"; // THE IMPORT OF DAO AVATAR ICON MUST BE LAST export * from "@/shared/components/icons/DaoAvatarIcon"; export * from "@/shared/components/icons/CookieBackground"; diff --git a/apps/dashboard/shared/dao-config/index.ts b/apps/dashboard/shared/dao-config/index.ts index 17eb664a6..eee944f9b 100644 --- a/apps/dashboard/shared/dao-config/index.ts +++ b/apps/dashboard/shared/dao-config/index.ts @@ -6,6 +6,7 @@ import { SCR } from "@/shared/dao-config/scr"; import { COMP } from "@/shared/dao-config/comp"; import { OBOL } from "@/shared/dao-config/obol"; import { NOUNS } from "@/shared/dao-config/nouns"; +import { ZK } from "@/shared/dao-config/zk"; export default { UNI, @@ -16,4 +17,5 @@ export default { NOUNS, COMP, OBOL, + ZK, } as const; diff --git a/apps/dashboard/shared/dao-config/types.ts b/apps/dashboard/shared/dao-config/types.ts index a98fc4794..210d04cee 100644 --- a/apps/dashboard/shared/dao-config/types.ts +++ b/apps/dashboard/shared/dao-config/types.ts @@ -177,6 +177,7 @@ export interface DaoAddresses { scrUSDC: Address; }; [DaoIdEnum.OBOL]: Record; + [DaoIdEnum.ZK]: Record; } export interface AttackProfitabilityConfig { diff --git a/apps/dashboard/shared/dao-config/zk.ts b/apps/dashboard/shared/dao-config/zk.ts new file mode 100644 index 000000000..4d1140e21 --- /dev/null +++ b/apps/dashboard/shared/dao-config/zk.ts @@ -0,0 +1,216 @@ +import { DaoConfiguration } from "@/shared/dao-config/types"; +import { RiskLevel, GovernanceImplementationEnum } from "@/shared/types/enums"; +import { GOVERNANCE_IMPLEMENTATION_CONSTANTS } from "@/shared/constants/governance-implementations"; +import { ZKIcon } from "@/shared/components/icons"; +import { zksync } from "viem/chains"; + +export const ZK: DaoConfiguration = { + name: "ZKSync", + decimals: 18, + color: { + svgColor: "#000000", + svgBgColor: "#FFFFFF", + }, + icon: ZKIcon, + daoOverview: { + token: "ERC20", + chain: { ...zksync, icon: ZKIcon }, + contracts: { + governor: "0xb83FF6501214ddF40C91C9565d095400f3F45746", + token: "0x5A7d6b2F92C77FAD6CCaBd7EE0624E64907Eaf3E", + timelock: "0xe5d21A9179CA2E1F0F327d598D464CcF60d89c3d", + }, + rules: { + delay: true, + changeVote: false, + timelock: true, + cancelFunction: true, + logic: "For + Abstain", + quorumCalculation: "3% Minted Supply (630M $ZK)", + proposalThreshold: "210M (0,1% Minted Supply)", + }, + }, + attackProfitability: { + riskLevel: RiskLevel.LOW, + supportsLiquidTreasuryCall: false, + attackCostBarChart: {}, + }, + 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: "zkSync contracts are audited.", + }, + [GovernanceImplementationEnum.INTERFACE_HIJACK]: { + value: "No", + riskLevel: RiskLevel.HIGH, + description: + GOVERNANCE_IMPLEMENTATION_CONSTANTS[ + GovernanceImplementationEnum.INTERFACE_HIJACK + ].description, + 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).", + }, + [GovernanceImplementationEnum.ATTACK_PROFITABILITY]: { + value: "<$10K USD", + riskLevel: RiskLevel.LOW, + description: + GOVERNANCE_IMPLEMENTATION_CONSTANTS[ + GovernanceImplementationEnum.ATTACK_PROFITABILITY + ].description, + riskExplanation: + "zkSync does not maintain a liquid treasury. The only assets under the DAO's control are governance tokens ($ZK).", + }, + [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.", + }, + [GovernanceImplementationEnum.PROPOSAL_THRESHOLD]: { + value: "1M $ZK", + 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: "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.LOW, + description: + GOVERNANCE_IMPLEMENTATION_CONSTANTS[ + GovernanceImplementationEnum.SECURITY_COUNCIL + ].description, + riskExplanation: "zkSync has a Security Council.", + }, + [GovernanceImplementationEnum.SPAM_RESISTANCE]: { + value: "No", + riskLevel: RiskLevel.HIGH, + description: + GOVERNANCE_IMPLEMENTATION_CONSTANTS[ + GovernanceImplementationEnum.SPAM_RESISTANCE + ].description, + requirements: [ + "ZkSync 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: "ZkSync governance is vulnerable to spam proposals.", + }, + [GovernanceImplementationEnum.TIMELOCK_ADMIN]: { + value: "Yes", + riskLevel: RiskLevel.LOW, + description: + GOVERNANCE_IMPLEMENTATION_CONSTANTS[ + GovernanceImplementationEnum.TIMELOCK_ADMIN + ].description, + riskExplanation: "The Timelock is controlled by the Governor.", + }, + [GovernanceImplementationEnum.TIMELOCK_DELAY]: { + value: "6 days", + riskLevel: RiskLevel.LOW, + description: + GOVERNANCE_IMPLEMENTATION_CONSTANTS[ + GovernanceImplementationEnum.TIMELOCK_DELAY + ].description, + riskExplanation: "Six days is a sufficient delay for Timelock.", + }, + [GovernanceImplementationEnum.VETO_STRATEGY]: { + value: "Yes", + riskLevel: RiskLevel.LOW, + description: + GOVERNANCE_IMPLEMENTATION_CONSTANTS[ + GovernanceImplementationEnum.VETO_STRATEGY + ].description, + riskExplanation: + "The zkSync Security Council aligns with leading security council standards.", + }, + [GovernanceImplementationEnum.VOTE_MUTABILITY]: { + value: "No", + riskLevel: RiskLevel.MEDIUM, + description: + GOVERNANCE_IMPLEMENTATION_CONSTANTS[ + GovernanceImplementationEnum.VOTE_MUTABILITY + ].description, + requirements: [ + "zkSync must allow votes to be changed even after they have been cast.", + ], + riskExplanation: + "The lack of vote mutability jeopardizes DAO decisions if its main voting interface is attacked.", + }, + [GovernanceImplementationEnum.VOTING_DELAY]: { + value: "6 days", + riskLevel: RiskLevel.LOW, + description: + GOVERNANCE_IMPLEMENTATION_CONSTANTS[ + GovernanceImplementationEnum.VOTING_DELAY + ].description, + riskExplanation: "Six days is a sufficient delay for Voting Delay.", + }, + [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.", + }, + [GovernanceImplementationEnum.VOTING_PERIOD]: { + value: "6 days", + riskLevel: RiskLevel.LOW, + description: + GOVERNANCE_IMPLEMENTATION_CONSTANTS[ + GovernanceImplementationEnum.VOTING_PERIOD + ].description, + riskExplanation: + "Six days is enough time for the DAO to organize itself against an attack during the voting period..", + }, + [GovernanceImplementationEnum.VOTING_SUBSIDY]: { + value: "No", + riskLevel: RiskLevel.HIGH, + description: + GOVERNANCE_IMPLEMENTATION_CONSTANTS[ + GovernanceImplementationEnum.VOTING_SUBSIDY + ].description, + 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.", + }, + }, + }, + riskAnalysis: true, + resilienceStages: true, + tokenDistribution: true, + dataTables: true, +}; diff --git a/apps/dashboard/shared/types/daos.ts b/apps/dashboard/shared/types/daos.ts index f8ed43d4f..546cece68 100644 --- a/apps/dashboard/shared/types/daos.ts +++ b/apps/dashboard/shared/types/daos.ts @@ -7,6 +7,7 @@ export enum DaoIdEnum { SCR = "SCR", COMP = "COMP", OBOL = "OBOL", + ZK = "ZK", } export interface DAO {