Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
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
3 changes: 1 addition & 2 deletions .github/workflows/build-from-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,6 @@ jobs:
docker load -i '/tmp/image-${{ matrix.name }}-${{ env.ENVIRONMENT }}.tar'
rm -rf '/tmp/image-${{ matrix.name }}-${{ env.ENVIRONMENT }}.tar'
docker push ${{ steps.image_lowercase.outputs.lowercase }}-${{ env.CLEAN_NETWORK}}:${{ env.COMMIT_TAG }}
docker push ${{ steps.image_lowercase.outputs.lowercase }}-${{ env.CLEAN_NETWORK}}:${{ env.STATIC_TAG }}

- name: Notify Qovery of new image tag
run: |
Expand All @@ -202,7 +201,7 @@ jobs:
-d '{
"image_name": "${{ steps.image_lowercase.outputs.lowercase }}-${{ env.CLEAN_NETWORK }}",
"tag": "${{ env.COMMIT_TAG }}"
}'
}'

- name: Add tag as a PR comment
uses: ubie-oss/[email protected]
Expand Down
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
18 changes: 14 additions & 4 deletions govtool/frontend/package-lock.json

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

3 changes: 2 additions & 1 deletion govtool/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@
"@hookform/resolvers": "^3.3.1",
"@intersect.mbo/govtool-outcomes-pillar-ui": "v1.5.0",
"@intersect.mbo/intersectmbo.org-icons-set": "^1.0.8",
"@intersect.mbo/pdf-ui": "1.0.3-alfa",
"@intersect.mbo/pdf-ui": "1.0.3-beta",
"@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
Loading