Skip to content

Commit 2e5d2a7

Browse files
committed
feat: support for revealing shutter commit from the frontend
1 parent e983fdd commit 2e5d2a7

File tree

3 files changed

+113
-6
lines changed

3 files changed

+113
-6
lines changed
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import React, { useCallback, useMemo, useState } from "react";
2+
import styled from "styled-components";
3+
4+
import { Button } from "@kleros/ui-components-library";
5+
import { useWalletClient, usePublicClient } from "wagmi";
6+
import { useParams } from "react-router-dom";
7+
import { useLocalStorage } from "react-use";
8+
9+
import { wrapWithToast } from "utils/wrapWithToast";
10+
import { isUndefined } from "utils/index";
11+
12+
import { useSimulateDisputeKitShutterCastVoteShutter } from "hooks/contracts/generated";
13+
14+
const Container = styled.div`
15+
width: 100%;
16+
height: auto;
17+
display: flex;
18+
justify-content: center;
19+
margin-top: 16px;
20+
`;
21+
22+
interface IReveal {
23+
voteIDs: string[];
24+
setIsOpen: (val: boolean) => void;
25+
}
26+
27+
const Reveal: React.FC<IReveal> = ({ voteIDs, setIsOpen }) => {
28+
const { id } = useParams();
29+
const parsedDisputeID = useMemo(() => BigInt(id ?? 0), [id]);
30+
const parsedVoteIDs = useMemo(() => voteIDs.map((voteID) => BigInt(voteID)), [voteIDs]);
31+
const saltKey = useMemo(() => `shutter-dispute-${id}-voteids-${voteIDs}`, [id, voteIDs]);
32+
33+
const [storedData, _, removeStoredData] = useLocalStorage(saltKey);
34+
35+
const { data: walletClient } = useWalletClient();
36+
const publicClient = usePublicClient();
37+
38+
const [isRevealing, setIsRevealing] = useState(false);
39+
40+
const parsedStoredData = useMemo(() => {
41+
if (isUndefined(storedData)) return undefined;
42+
try {
43+
const data = JSON.parse(storedData);
44+
if (!data.salt || !data.choice || !data.justification) {
45+
throw new Error("Invalid stored data");
46+
}
47+
return data;
48+
} catch (error) {
49+
console.error("Error parsing stored data:", error);
50+
return undefined;
51+
}
52+
}, [storedData]);
53+
54+
const {
55+
data: simulateData,
56+
isLoading: isSimulating,
57+
error: simulateError,
58+
} = useSimulateDisputeKitShutterCastVoteShutter({
59+
query: {
60+
enabled: !isUndefined(parsedStoredData),
61+
},
62+
args: [
63+
parsedDisputeID,
64+
parsedVoteIDs,
65+
BigInt(parsedStoredData?.choice ?? 0),
66+
BigInt(parsedStoredData?.salt ?? 0),
67+
parsedStoredData?.justification ?? "",
68+
],
69+
});
70+
71+
const handleReveal = useCallback(async () => {
72+
if (isUndefined(parsedStoredData) || isUndefined(simulateData)) {
73+
console.error("No committed vote found or simulation not ready.");
74+
return;
75+
}
76+
77+
setIsRevealing(true);
78+
try {
79+
const { request } = simulateData;
80+
if (walletClient && publicClient) {
81+
await wrapWithToast(async () => await walletClient.writeContract(request), publicClient).then(({ status }) => {
82+
if (status) {
83+
removeStoredData();
84+
}
85+
setIsOpen(status);
86+
});
87+
}
88+
} catch (error) {
89+
console.error("Error revealing vote:", error);
90+
} finally {
91+
setIsRevealing(false);
92+
}
93+
}, [parsedStoredData, simulateData, walletClient, publicClient, setIsOpen, removeStoredData]);
94+
95+
return (
96+
<Container>
97+
{!isUndefined(parsedStoredData) ? (
98+
<Button
99+
text="Reveal Your Vote"
100+
onClick={handleReveal}
101+
disabled={isSimulating || !isUndefined(simulateError) || isRevealing}
102+
isLoading={isRevealing}
103+
/>
104+
) : null}
105+
</Container>
106+
);
107+
};
108+
109+
export default Reveal;

web/src/pages/Cases/CaseDetails/Voting/Shutter/Vote.tsx

Lines changed: 0 additions & 5 deletions
This file was deleted.

web/src/pages/Cases/CaseDetails/Voting/Shutter/index.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { useVotingContext } from "hooks/useVotingContext";
77
import { DisputeDetailsQuery, useDisputeDetailsQuery } from "queries/useDisputeDetailsQuery";
88

99
import ShutterCommit from "./Commit";
10+
import Reveal from "./Reveal";
1011

1112
interface IShutter {
1213
arbitrable: `0x${string}`;
@@ -20,11 +21,13 @@ const Shutter: React.FC<IShutter> = ({ arbitrable, setIsOpen, dispute, currentPe
2021
const { address } = useAccount();
2122
const { data: disputeData } = useDisputeDetailsQuery(id);
2223
const { data: drawData, refetch } = useDrawQuery(address?.toLowerCase(), id, disputeData?.dispute?.currentRound.id);
23-
const { isCommitPeriod, commited } = useVotingContext();
24+
const { isCommitPeriod, isVotingPeriod, commited } = useVotingContext();
2425
const voteIDs = useMemo(() => drawData?.draws?.map((draw) => draw.voteIDNum) as string[], [drawData]);
2526

2627
return id && isCommitPeriod && !commited ? (
2728
<ShutterCommit {...{ arbitrable, setIsOpen, voteIDs, refetch, dispute, currentPeriodIndex }} />
29+
) : id && isVotingPeriod ? (
30+
<Reveal {...{ setIsOpen, voteIDs }} />
2831
) : null;
2932
};
3033

0 commit comments

Comments
 (0)