Skip to content

Commit d0e1ea9

Browse files
committed
(feat#3745): support ed25519 author signature validation on gov actions
1 parent b7deafb commit d0e1ea9

File tree

12 files changed

+225
-3
lines changed

12 files changed

+225
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ changes.
1414

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

1819
### Fixed
1920

govtool/backend/sql/list-proposals.sql

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@ SELECT
304304
COALESCE(cv.ccAbstainVotes, 0) cc_abstain_votes,
305305
prev_gov_action.index as prev_gov_action_index,
306306
encode(prev_gov_action_tx.hash, 'hex') as prev_gov_action_tx_hash,
307+
off_chain_vote_data.json ->> 'body' AS body,
307308
COALESCE(
308309
json_agg(
309310
json_build_object(
@@ -367,4 +368,5 @@ GROUP BY
367368
off_chain_vote_gov_action_data.title,
368369
off_chain_vote_gov_action_data.abstract,
369370
off_chain_vote_gov_action_data.motivation,
370-
off_chain_vote_gov_action_data.rationale;
371+
off_chain_vote_gov_action_data.rationale,
372+
off_chain_vote_data.json ->> 'body';

govtool/backend/src/VVA/API.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ proposalToResponse timeZone Types.Proposal {..} =
245245
proposalResponseCcAbstainVotes = proposalCcAbstainVotes,
246246
proposalResponsePrevGovActionIndex = proposalPrevGovActionIndex,
247247
proposalResponsePrevGovActionTxHash = HexText <$> proposalPrevGovActionTxHash,
248+
proposalResponseBody = proposalBody,
248249
proposalResponseAuthors = ProposalAuthors <$> proposalAuthors
249250
}
250251

govtool/backend/src/VVA/API/Types.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,7 @@ data ProposalResponse
401401
, proposalResponseCcAbstainVotes :: Integer
402402
, proposalResponsePrevGovActionIndex :: Maybe Integer
403403
, proposalResponsePrevGovActionTxHash :: Maybe HexText
404+
, proposalResponseBody :: Maybe Text
404405
, proposalResponseAuthors :: Maybe ProposalAuthors
405406
}
406407
deriving (Generic, Show)

govtool/backend/src/VVA/Types.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ data Proposal
208208
, proposalCcAbstainVotes :: Integer
209209
, proposalPrevGovActionIndex :: Maybe Integer
210210
, proposalPrevGovActionTxHash :: Maybe Text
211+
, proposalBody :: Maybe Text
211212
, proposalAuthors :: Maybe Value
212213
}
213214
deriving (Show)
@@ -242,6 +243,7 @@ instance FromRow Proposal where
242243
<*> (floor @Scientific <$> field) -- proposalCcAbstainVotes
243244
<*> field -- prevGovActionIndex
244245
<*> field -- prevGovActionTxHash
246+
<*> field -- proposalBody
245247
<*> field -- proposalAuthors
246248

247249
data TransactionStatus = TransactionStatus

govtool/frontend/package-lock.json

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

govtool/frontend/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
"@intersect.mbo/pdf-ui": "1.0.1-alfa",
3333
"@mui/icons-material": "^5.14.3",
3434
"@mui/material": "^5.14.4",
35+
"@noble/ed25519": "^2.3.0",
3536
"@rollup/plugin-babel": "^6.0.4",
3637
"@rollup/pluginutils": "^5.1.0",
3738
"@sentry/react": "^7.77.0",

govtool/frontend/src/components/organisms/GovernanceActionDetailsCardData.tsx

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
import { useMemo, useState, Fragment } from "react";
1+
import { useMemo, useState, Fragment, useEffect } from "react";
22
import { Box, Tabs, Tab, styled, Skeleton } from "@mui/material";
33
import { useLocation } from "react-router-dom";
4+
import CheckCircleIcon from "@mui/icons-material/CheckCircle";
5+
import CancelIcon from "@mui/icons-material/Cancel";
46

57
import { CopyButton, ExternalModalButton, Tooltip, Typography } from "@atoms";
68
import {
@@ -23,6 +25,7 @@ import {
2325
getFullGovActionId,
2426
mapArrayToObjectByKeys,
2527
encodeCIP129Identifier,
28+
validateSignature,
2629
} from "@utils";
2730
import { MetadataValidationStatus, ProposalData } from "@models";
2831
import { GovernanceActionType } from "@/types/governanceAction";
@@ -77,6 +80,7 @@ export const GovernanceActionDetailsCardData = ({
7780
proposal: {
7881
abstract,
7982
authors,
83+
body,
8084
createdDate,
8185
createdEpochNo,
8286
details,
@@ -386,7 +390,21 @@ export const GovernanceActionDetailsCardData = ({
386390
placement="bottom-end"
387391
arrow
388392
>
389-
<span>{author.name}</span>
393+
<span
394+
style={{
395+
display: "inline-flex",
396+
alignItems: "center",
397+
gap: 2,
398+
}}
399+
>
400+
<AuthorSignatureStatus
401+
signature={author.signature}
402+
publicKey={author.publicKey}
403+
algorithm={author.witnessAlgorithm}
404+
body={body}
405+
/>
406+
{author.name}
407+
</span>
390408
</Tooltip>
391409
{idx < arr.length - 1 && <span>,&nbsp;</span>}
392410
</Fragment>
@@ -498,3 +516,48 @@ const HardforkDetailsTabContent = ({
498516
</Box>
499517
);
500518
};
519+
520+
const AuthorSignatureStatus = ({
521+
algorithm,
522+
publicKey,
523+
signature,
524+
body,
525+
}: {
526+
algorithm?: string;
527+
publicKey?: string;
528+
signature?: string;
529+
body?: string;
530+
}) => {
531+
const [isSignatureValid, setIsSignatureValid] = useState<boolean | null>(
532+
null,
533+
);
534+
535+
useEffect(() => {
536+
let cancelled = false;
537+
async function checkSignature() {
538+
const args = {
539+
message: body,
540+
algorithm,
541+
publicKey:
542+
"6A29D3C5C6280FBD9EF17EFFB29F8E8435D404BCF2FCED9336ABAEF1D06B62CB",
543+
signature:
544+
"23CFF1D1DA358AF8D835CD2F1F2A972D6E09DA5BD05C08E076017F83FEF1CAC082A853C12E7EA6BB44FC322809E6554ED69302CEE03DF6ABEF2C9D709C0E8906",
545+
};
546+
const result = await validateSignature(args);
547+
if (!cancelled) setIsSignatureValid(result);
548+
}
549+
checkSignature();
550+
return () => {
551+
cancelled = true;
552+
};
553+
}, [algorithm, body, publicKey, signature]);
554+
555+
if (isSignatureValid === null) {
556+
return <Skeleton variant="text" width={16} />;
557+
}
558+
return isSignatureValid ? (
559+
<CheckCircleIcon sx={{ color: "success.main", fontSize: 16 }} />
560+
) : (
561+
<CancelIcon sx={{ color: "error.main", fontSize: 16 }} />
562+
);
563+
};

govtool/frontend/src/models/api.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,9 @@ export type ProposalData = {
239239
witnessAlgorithm?: string;
240240
publicKey?: string;
241241
signature?: string;
242+
isSignatureValid?: boolean;
242243
}[];
244+
body?: string;
243245
} & SubmittedVotesData;
244246

245247
export type NewConstitutionAnchor = {

govtool/frontend/src/utils/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,4 @@ export * from "./uniqBy";
3737
export * from "./wait";
3838
export * from "./getBase64ImageDetails";
3939
export * from "./parseBoolean";
40+
export * from "./validateSignature";

0 commit comments

Comments
 (0)