Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ changes.

- Preserve maintenance ending banner state on the wallet connection change [Issue 3681](https://github.com/IntersectMBO/govtool/issues/3681)
- Add authors for Live Voting Governance Actions [Issue 3745](https://github.com/IntersectMBO/govtool/issues/3745)
- Add support for ed25519 author signature validation on gov actions [Issue 3745](https://github.com/IntersectMBO/govtool/issues/3745)

### Fixed

Expand Down
4 changes: 3 additions & 1 deletion govtool/backend/sql/list-proposals.sql
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ SELECT
COALESCE(cv.ccAbstainVotes, 0) cc_abstain_votes,
prev_gov_action.index as prev_gov_action_index,
encode(prev_gov_action_tx.hash, 'hex') as prev_gov_action_tx_hash,
off_chain_vote_data.json as json_content,
COALESCE(
json_agg(
json_build_object(
Expand Down Expand Up @@ -367,4 +368,5 @@ GROUP BY
off_chain_vote_gov_action_data.title,
off_chain_vote_gov_action_data.abstract,
off_chain_vote_gov_action_data.motivation,
off_chain_vote_gov_action_data.rationale;
off_chain_vote_gov_action_data.rationale,
off_chain_vote_data.json;
1 change: 1 addition & 0 deletions govtool/backend/src/VVA/API.hs
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ proposalToResponse timeZone Types.Proposal {..} =
proposalResponseCcAbstainVotes = proposalCcAbstainVotes,
proposalResponsePrevGovActionIndex = proposalPrevGovActionIndex,
proposalResponsePrevGovActionTxHash = HexText <$> proposalPrevGovActionTxHash,
proposalResponseJson = proposalJson,
proposalResponseAuthors = ProposalAuthors <$> proposalAuthors
}

Expand Down
1 change: 1 addition & 0 deletions govtool/backend/src/VVA/API/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,7 @@ data ProposalResponse
, proposalResponseCcAbstainVotes :: Integer
, proposalResponsePrevGovActionIndex :: Maybe Integer
, proposalResponsePrevGovActionTxHash :: Maybe HexText
, proposalResponseJson :: Maybe Value
, proposalResponseAuthors :: Maybe ProposalAuthors
}
deriving (Generic, Show)
Expand Down
2 changes: 2 additions & 0 deletions govtool/backend/src/VVA/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ data Proposal
, proposalCcAbstainVotes :: Integer
, proposalPrevGovActionIndex :: Maybe Integer
, proposalPrevGovActionTxHash :: Maybe Text
, proposalJson :: Maybe Value
, proposalAuthors :: Maybe Value
}
deriving (Show)
Expand Down Expand Up @@ -242,6 +243,7 @@ instance FromRow Proposal where
<*> (floor @Scientific <$> field) -- proposalCcAbstainVotes
<*> field -- prevGovActionIndex
<*> field -- prevGovActionTxHash
<*> field -- proposalJson
<*> field -- proposalAuthors

data TransactionStatus = TransactionStatus
Expand Down
10 changes: 10 additions & 0 deletions govtool/frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions govtool/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"@intersect.mbo/pdf-ui": "1.0.1-alfa",
"@mui/icons-material": "^5.14.3",
"@mui/material": "^5.14.4",
"@noble/ed25519": "^2.3.0",
"@rollup/plugin-babel": "^6.0.4",
"@rollup/pluginutils": "^5.1.0",
"@sentry/react": "^7.77.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { useMemo, useState, Fragment } from "react";
import { useMemo, useState, useEffect } from "react";
import { Box, Tabs, Tab, styled, Skeleton } from "@mui/material";
import { useLocation } from "react-router-dom";
import CheckCircleOutlineIcon from "@mui/icons-material/CheckCircleOutline";
import CancelOutlinedIcon from "@mui/icons-material/CancelOutlined";
import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined";

import { CopyButton, ExternalModalButton, Tooltip, Typography } from "@atoms";
import {
Expand All @@ -23,8 +26,10 @@ import {
getFullGovActionId,
mapArrayToObjectByKeys,
encodeCIP129Identifier,
validateSignature,
} from "@utils";
import { MetadataValidationStatus, ProposalData } from "@models";
import { errorRed, successGreen } from "@/consts";
import { GovernanceActionType } from "@/types/governanceAction";
import { useAppContext } from "@/context";

Expand Down Expand Up @@ -77,6 +82,7 @@ export const GovernanceActionDetailsCardData = ({
proposal: {
abstract,
authors,
json: jsonContent,
createdDate,
createdEpochNo,
details,
Expand Down Expand Up @@ -369,28 +375,39 @@ export const GovernanceActionDetailsCardData = ({
<GovernanceActionCardElement
label={t("govActions.authors.title")}
text={
(authors ?? []).length <= 0
? t("govActions.authors.noDataAvailable")
: (authors ?? []).map((author, idx, arr) => (
<Fragment key={author.publicKey}>
<Tooltip
heading={`${t("govActions.authors.witnessAlgorithm")}: ${
author.witnessAlgorithm
}`}
paragraphOne={`${t("govActions.authors.publicKey")}: ${
author.publicKey
}`}
paragraphTwo={`${t("govActions.authors.signature")}: ${
author.signature
}`}
placement="bottom-end"
arrow
<Box sx={{ display: "flex", gap: 2, flexWrap: "wrap" }}>
{(authors ?? []).length <= 0
? t("govActions.authors.noDataAvailable")
: (authors ?? []).map((author) => (
<Box
key={author.publicKey}
sx={{ display: "flex", gap: 0.5, alignItems: "center" }}
>
<AuthorSignatureStatus
signature={author.signature}
publicKey={author.publicKey}
algorithm={author.witnessAlgorithm}
jsonContent={jsonContent}
/>
<span>{author.name}</span>
</Tooltip>
{idx < arr.length - 1 && <span>,&nbsp;</span>}
</Fragment>
))
<Tooltip
heading={`${t("govActions.authors.witnessAlgorithm")}: ${
author.witnessAlgorithm
}`}
paragraphOne={`${t("govActions.authors.publicKey")}: ${
author.publicKey
}`}
paragraphTwo={`${t("govActions.authors.signature")}: ${
author.signature
}`}
placement="bottom-end"
arrow
>
<InfoOutlinedIcon fontSize="small" />
</Tooltip>
</Box>
))}
</Box>
}
textVariant="longText"
dataTestId="authors"
Expand Down Expand Up @@ -498,3 +515,62 @@ const HardforkDetailsTabContent = ({
</Box>
);
};

const AuthorSignatureStatus = ({
algorithm,
publicKey,
signature,
jsonContent,
}: {
algorithm?: string;
publicKey?: string;
signature?: string;
jsonContent?: Record<string, unknown>;
}) => {
const { t } = useTranslation();
const [isSignatureValid, setIsSignatureValid] = useState<boolean | null>(
null,
);

useEffect(() => {
let cancelled = false;
async function checkSignature() {
const args = {
jsonContent,
algorithm,
publicKey,
signature,
};
const result = await validateSignature(args);
if (!cancelled) setIsSignatureValid(result);
}
checkSignature();
return () => {
cancelled = true;
};
}, [algorithm, jsonContent, publicKey, signature]);

if (isSignatureValid === null) {
return <Skeleton variant="text" width={16} />;
}
return (
<Tooltip
heading={
isSignatureValid
? t("govActions.authors.singatureVerified")
: t("govActions.authors.signatureNotVerified")
}
placement="bottom-end"
arrow
>
{isSignatureValid ? (
<CheckCircleOutlineIcon
sx={{ color: successGreen.c500 }}
fontSize="small"
/>
) : (
<CancelOutlinedIcon sx={{ color: errorRed.c500 }} fontSize="small" />
)}
</Tooltip>
);
};
6 changes: 4 additions & 2 deletions govtool/frontend/src/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -423,10 +423,12 @@
"anchorHash": "Metadata anchor hash",
"authors": {
"noDataAvailable": "No data available",
"title": "Authors",
"title": "Author(s)",
"publicKey": "Public Key",
"signature": "Signature",
"witnessAlgorithm": "Witness Algorithm"
"witnessAlgorithm": "Witness Algorithm",
"singatureVerified": "Author signature is verified",
"signatureNotVerified": "Author signature is not verified"
},
"backToGovActions": "Back to Governance Actions",
"castVote": "<0>You voted {{vote}} on this proposal</0>\non {{date}} (Epoch {{epoch}})",
Expand Down
1 change: 1 addition & 0 deletions govtool/frontend/src/models/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ export type ProposalData = {
publicKey?: string;
signature?: string;
}[];
json?: Record<string, unknown>;
} & SubmittedVotesData;

export type NewConstitutionAnchor = {
Expand Down
1 change: 1 addition & 0 deletions govtool/frontend/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,4 @@ export * from "./uniqBy";
export * from "./wait";
export * from "./getBase64ImageDetails";
export * from "./parseBoolean";
export * from "./validateSignature";
Loading