Skip to content

Commit 8c74d4a

Browse files
committed
feat: decryption delay is the remaining of the commit period
1 parent 8bf3772 commit 8c74d4a

File tree

6 files changed

+38
-16
lines changed

6 files changed

+38
-16
lines changed

web/src/pages/Cases/CaseDetails/Timeline.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ const useTimeline = (dispute: DisputeDetailsQuery["dispute"], currentItemIndex:
141141
}));
142142
};
143143

144-
const getDeadline = (
144+
export const getDeadline = (
145145
currentPeriodIndex: number,
146146
lastPeriodChange?: string,
147147
timesPerPeriod?: string[]

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

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,15 @@ import { useWalletClient, usePublicClient, useConfig } from "wagmi";
88

99
import { simulateDisputeKitShutterCastCommitShutter } from "hooks/contracts/generated";
1010
import useSigningAccount from "hooks/useSigningAccount";
11+
import { useCountdown } from "hooks/useCountdown";
12+
import { DisputeDetailsQuery } from "queries/useDisputeDetailsQuery";
13+
1114
import { isUndefined } from "utils/index";
1215
import { encrypt } from "utils/shutter";
1316
import { wrapWithToast } from "utils/wrapWithToast";
1417

1518
import OptionsContainer from "../OptionsContainer";
19+
import { getDeadline } from "../../Timeline";
1620

1721
const Container = styled.div`
1822
width: 100%;
@@ -24,6 +28,8 @@ interface ICommit {
2428
voteIDs: string[];
2529
setIsOpen: (val: boolean) => void;
2630
refetch: () => void;
31+
dispute: DisputeDetailsQuery["dispute"];
32+
currentPeriodIndex: number;
2733
}
2834

2935
const SEPARATOR = "-";
@@ -47,7 +53,7 @@ const hashVote = (choice: bigint, salt: bigint, justification: string): `0x${str
4753
return keccak256(encodedParams);
4854
};
4955

50-
const Commit: React.FC<ICommit> = ({ arbitrable, voteIDs, setIsOpen, refetch }) => {
56+
const Commit: React.FC<ICommit> = ({ arbitrable, voteIDs, setIsOpen, refetch, dispute, currentPeriodIndex }) => {
5157
const { id } = useParams();
5258
const parsedDisputeID = useMemo(() => BigInt(id ?? 0), [id]);
5359
const parsedVoteIDs = useMemo(() => voteIDs.map((voteID) => BigInt(voteID)), [voteIDs]);
@@ -58,6 +64,12 @@ const Commit: React.FC<ICommit> = ({ arbitrable, voteIDs, setIsOpen, refetch })
5864
const [justification, setJustification] = useState("");
5965
const saltKey = useMemo(() => `shutter-dispute-${id}-voteids-${voteIDs}`, [id, voteIDs]);
6066
const [_, setSalt] = useLocalStorage(saltKey);
67+
const deadlineCommitPeriod = getDeadline(
68+
currentPeriodIndex,
69+
dispute?.lastPeriodChange,
70+
dispute?.court.timesPerPeriod
71+
);
72+
const countdownToVotingPeriod = useCountdown(deadlineCommitPeriod);
6173

6274
const handleCommit = useCallback(
6375
async (choice: bigint) => {
@@ -74,7 +86,9 @@ const Commit: React.FC<ICommit> = ({ arbitrable, voteIDs, setIsOpen, refetch })
7486
setSalt(JSON.stringify({ salt, choice: choice.toString(), justification }));
7587

7688
const encodedMessage = `${choice.toString()}${SEPARATOR}${salt}${SEPARATOR}${justification}`;
77-
const { encryptedCommitment, identity } = await encrypt(encodedMessage);
89+
// a minimum of 60 seconds of decryptionDelay is enforced to give the threshold crypto nodes time to coordinate
90+
const decryptionDelay = Math.max(countdownToVotingPeriod, 60);
91+
const { encryptedCommitment, identity } = await encrypt(encodedMessage, decryptionDelay);
7892

7993
const commitHash = hashVote(choice, BigInt(salt), justification);
8094

@@ -101,6 +115,7 @@ const Commit: React.FC<ICommit> = ({ arbitrable, voteIDs, setIsOpen, refetch })
101115
generateSigningAccount,
102116
signingAccount,
103117
refetch,
118+
countdownToVotingPeriod,
104119
]
105120
);
106121

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,28 @@ import { useAccount } from "wagmi";
44

55
import { useDrawQuery } from "hooks/queries/useDrawQuery";
66
import { useVotingContext } from "hooks/useVotingContext";
7-
import { useDisputeDetailsQuery } from "queries/useDisputeDetailsQuery";
7+
import { DisputeDetailsQuery, useDisputeDetailsQuery } from "queries/useDisputeDetailsQuery";
88

99
import ShutterCommit from "./Commit";
1010

1111
interface IShutter {
1212
arbitrable: `0x${string}`;
1313
setIsOpen: (val: boolean) => void;
14+
dispute: DisputeDetailsQuery["dispute"];
15+
currentPeriodIndex: number;
1416
}
1517

16-
const Shutter: React.FC<IShutter> = ({ arbitrable, setIsOpen }) => {
18+
const Shutter: React.FC<IShutter> = ({ arbitrable, setIsOpen, dispute, currentPeriodIndex }) => {
1719
const { id } = useParams();
1820
const { address } = useAccount();
1921
const { data: disputeData } = useDisputeDetailsQuery(id);
2022
const { data: drawData, refetch } = useDrawQuery(address?.toLowerCase(), id, disputeData?.dispute?.currentRound.id);
2123
const { isCommitPeriod, commited } = useVotingContext();
2224
const voteIDs = useMemo(() => drawData?.draws?.map((draw) => draw.voteIDNum) as string[], [drawData]);
2325

24-
return id && isCommitPeriod && !commited ? <ShutterCommit {...{ arbitrable, setIsOpen, voteIDs, refetch }} /> : null;
26+
return id && isCommitPeriod && !commited ? (
27+
<ShutterCommit {...{ arbitrable, setIsOpen, voteIDs, refetch, dispute, currentPeriodIndex }} />
28+
) : null;
2529
};
2630

2731
export default Shutter;

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { isUndefined } from "utils/index";
1515
import { isLastRound } from "utils/isLastRound";
1616

1717
import { useAppealCost } from "queries/useAppealCost";
18-
import { useDisputeDetailsQuery } from "queries/useDisputeDetailsQuery";
18+
import { DisputeDetailsQuery, useDisputeDetailsQuery } from "queries/useDisputeDetailsQuery";
1919

2020
import { responsiveSize } from "styles/responsiveSize";
2121
import { landscapeStyle } from "styles/landscapeStyle";
@@ -55,9 +55,10 @@ const useFinalDate = (lastPeriodChange: string, currentPeriodIndex?: number, tim
5555
interface IVoting {
5656
arbitrable?: `0x${string}`;
5757
currentPeriodIndex: number;
58+
dispute: DisputeDetailsQuery["dispute"];
5859
}
5960

60-
const Voting: React.FC<IVoting> = ({ arbitrable, currentPeriodIndex }) => {
61+
const Voting: React.FC<IVoting> = ({ arbitrable, currentPeriodIndex, dispute }) => {
6162
const { id } = useParams();
6263
const { isDisconnected } = useAccount();
6364
const { data: disputeData } = useDisputeDetailsQuery(id);
@@ -116,7 +117,9 @@ const Voting: React.FC<IVoting> = ({ arbitrable, currentPeriodIndex }) => {
116117
<>
117118
<VotingHistory {...{ arbitrable }} isQuestion={false} />
118119
{isClassicDisputeKit ? <Classic arbitrable={arbitrable ?? "0x0"} setIsOpen={setIsPopupOpen} /> : null}
119-
{isShutterDisputeKit ? <Shutter arbitrable={arbitrable ?? "0x0"} setIsOpen={setIsPopupOpen} /> : null}
120+
{isShutterDisputeKit ? (
121+
<Shutter arbitrable={arbitrable ?? "0x0"} setIsOpen={setIsPopupOpen} {...{ dispute, currentPeriodIndex }} />
122+
) : null}
120123
</>
121124
) : (
122125
<VotingHistory {...{ arbitrable }} isQuestion={true} />

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ const CaseDetails: React.FC = () => {
7979
}
8080
/>
8181
<Route path="evidence" element={<Evidence />} />
82-
<Route path="voting" element={<Voting {...{ arbitrable, currentPeriodIndex }} />} />
82+
<Route path="voting" element={<Voting {...{ arbitrable, currentPeriodIndex, dispute }} />} />
8383
<Route path="appeal" element={<Appeal {...{ currentPeriodIndex }} />} />
8484
<Route path="*" element={<Navigate to="overview" replace />} />
8585
</Routes>

web/src/utils/shutter.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
import { encryptData, decrypt as shutterDecrypt } from "@shutter-network/shutter-sdk";
22
import { stringToHex, hexToString, Hex } from "viem";
33

4-
// Time in seconds to wait before the message can be decrypted
5-
export const DECRYPTION_DELAY = 120;
6-
74
interface ShutterApiMessageData {
85
eon: number;
96
identity: string;
@@ -109,7 +106,7 @@ async function fetchDecryptionKey(identity: string): Promise<ShutterDecryptionKe
109106
if (jsonResponse?.description?.includes("timestamp not reached yet")) {
110107
throw new Error(
111108
`Cannot decrypt yet: The decryption timestamp has not been reached.\n` +
112-
`Please wait at least ${DECRYPTION_DELAY} seconds after encryption before attempting to decrypt.\n` +
109+
`Please wait until the commit period has ended before attempting to decrypt.\n` +
113110
`Error details: ${jsonResponse.description}`
114111
);
115112
}
@@ -155,9 +152,12 @@ function generateRandomBytes32(): `0x${string}` {
155152
* @param message The message to encrypt
156153
* @returns Promise with the encrypted commitment and identity
157154
*/
158-
export async function encrypt(message: string): Promise<{ encryptedCommitment: string; identity: string }> {
155+
export async function encrypt(
156+
message: string,
157+
decryptionDelay: number
158+
): Promise<{ encryptedCommitment: string; identity: string }> {
159159
// Set decryption timestamp
160-
const decryptionTimestamp = Math.floor(Date.now() / 1000) + DECRYPTION_DELAY;
160+
const decryptionTimestamp = Math.floor(Date.now() / 1000) + decryptionDelay;
161161

162162
// Fetch encryption data from Shutter API
163163
console.log(`Fetching encryption data for decryption at timestamp ${decryptionTimestamp}...`);

0 commit comments

Comments
 (0)