Skip to content

Commit

Permalink
Merge pull request #2040 from zeitgeistpm/tr-court-work-2
Browse files Browse the repository at this point in the history
More court improvements
  • Loading branch information
yornaath authored Dec 12, 2023
2 parents f32ba89 + f86f762 commit 7eddc1c
Show file tree
Hide file tree
Showing 17 changed files with 420 additions and 104 deletions.
42 changes: 42 additions & 0 deletions components/court/CourtAppealForm.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
import { Disclosure } from "@headlessui/react";
import { useQueryClient } from "@tanstack/react-query";
import { isRpcSdk } from "@zeitgeistpm/sdk";
import TransactionButton from "components/ui/TransactionButton";
import Decimal from "decimal.js";
import { useCourtCase } from "lib/hooks/queries/court/useCourtCase";
import { courtCasesRootKey } from "lib/hooks/queries/court/useCourtCases";
import { useChainConstants } from "lib/hooks/queries/useChainConstants";
import { useExtrinsic } from "lib/hooks/useExtrinsic";
import { useSdkv2 } from "lib/hooks/useSdkv2";
import { useMemo } from "react";
import { AiOutlineEye } from "react-icons/ai";

export const CourtAppealForm = ({ caseId }: { caseId: number }) => {
const [sdk, id] = useSdkv2();
const queryClient = useQueryClient();
const { data: chainConstants } = useChainConstants();
const { data: courtCase } = useCourtCase(caseId);

const { send, isReady, isLoading, isBroadcasting } = useExtrinsic(
() => {
Expand All @@ -23,6 +31,13 @@ export const CourtAppealForm = ({ caseId }: { caseId: number }) => {
},
);

const bond = useMemo(() => {
const appealRound = (courtCase?.appeals.length ?? 0) + 1;
return new Decimal(chainConstants?.court.appealBond ?? 0)
.mul(Math.pow(2, appealRound))
.toNumber();
}, [courtCase, chainConstants]);

return (
<div className="overflow-hidden rounded-xl shadow-lg">
<div className="center flex bg-fog-of-war py-3">
Expand All @@ -37,6 +52,33 @@ export const CourtAppealForm = ({ caseId }: { caseId: number }) => {
</div>
</div>

<div className="relative mb-5 mt-4 w-full rounded-lg bg-provincial-pink p-5 text-sm font-normal">
<div>
When you appeal you have to bond{" "}
<b>
{bond} {chainConstants?.tokenSymbol}
</b>
.
</div>
<Disclosure>
<Disclosure.Button className="py-2">
<div className="center cursor-pointer gap-2 text-xs text-gray-500">
Show Details <AiOutlineEye size={12} />
</div>
</Disclosure.Button>
<Disclosure.Panel className="text-gray-500">
If no further appeals are made after the appeal period finishes,
accounts that appealed when the outcome was incorrect will be
refunded. Accounts that appealed when the outcome was correct will
be slashed.
<br />
<br />
Once four appeals have been made the global dispute system will be
actived to resolve the case.
</Disclosure.Panel>
</Disclosure>
</div>

<TransactionButton
disabled={!isReady || isLoading || isBroadcasting}
className={`relative h-[56px] ${
Expand Down
6 changes: 3 additions & 3 deletions components/court/CourtCasesTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -353,13 +353,13 @@ const caseStatusCopy: Record<
},
appeal: {
title: "Appeal",
description: "Jurors can now appeal the voted outcome.",
description: "The case can now be appealed.",
color: "text-orange-400",
},
reassigned: {
title: "Reassigned",
title: "Settled",
description:
"All juror and delegator stakes were reassigned, by losers paying the winners.",
"The case is settled and stakes were reassigned by losers paying the winners.",
color: "text-gray-400",
},
closed: {
Expand Down
82 changes: 72 additions & 10 deletions components/court/CourtStageTimer.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,41 @@
import { isInfinity } from "@zeitgeistpm/utility/dist/infinity";
import * as Time from "@zeitgeistpm/utility/dist/time";
import Skeleton from "components/ui/Skeleton";
import { FullMarketFragment } from "@zeitgeistpm/indexer";
import { useCaseMarketId } from "lib/hooks/queries/court/useCaseMarketId";
import { useCourtCase } from "lib/hooks/queries/court/useCourtCase";
import { useMarket } from "lib/hooks/queries/useMarket";
import { useChainTime } from "lib/state/chaintime";
import { CourtStage } from "lib/state/court/get-stage";
import { CourtStage, getCourtStage } from "lib/state/court/get-stage";
import moment from "moment";
import { useMemo } from "react";
import InfoPopover from "components/ui/InfoPopover";
import { CourtAppealRound } from "lib/state/court/types";

export const CourtStageTimer = ({ stage }: { stage?: CourtStage }) => {
export const CourtStageTimer = ({
market: initialMarket,
caseId,
}: {
market?: FullMarketFragment;
caseId: number;
}) => {
const time = useChainTime();

const { data: courtCase } = useCourtCase(caseId);
const { data: marketId } = useCaseMarketId(caseId);

let { data: dynamicMarket } = useMarket(
marketId != null ? { marketId } : undefined,
);

const market = dynamicMarket ?? initialMarket;

const stage = useMemo(() => {
if (time && market && courtCase) {
return getCourtStage(time, market, courtCase);
}
}, [time, market, courtCase]);

const timeLeft = useMemo(() => {
if (!time || !stage) return undefined;
const left = Time.toMs(time, { start: 0, end: stage.remainingBlocks });
Expand All @@ -23,6 +50,10 @@ export const CourtStageTimer = ({ stage }: { stage?: CourtStage }) => {
? 100
: ((stage.totalTime - stage.remainingBlocks) / stage.totalTime) * 100;

const round = courtCase
? (courtCase.appeals.length as CourtAppealRound)
: undefined;

return (
<>
<div className="inline-block w-full">
Expand All @@ -33,11 +64,21 @@ export const CourtStageTimer = ({ stage }: { stage?: CourtStage }) => {
<div className="text-sm text-sky-600">
{courtStageCopy[stage.type].description}
</div>
{stage.type !== "closed" && stage.type !== "reassigned" && (
<div className="ml-auto text-right text-black">
{timeLeft?.humanize()} left
</div>
)}
<div className="ml-auto flex items-center gap-2">
{stage.type !== "closed" && stage.type !== "reassigned" && (
<div className=" text-right text-black">
{timeLeft?.humanize()} left
</div>
)}
{round && (
<div
className={`flex items-center gap-1 rounded-full px-2 py-1 text-xs ${roundCopy[round].className}`}
>
Round {round}{" "}
<InfoPopover>{roundCopy[round].description}</InfoPopover>
</div>
)}
</div>
</div>
<div className="w-full">
<div className="text-right text-xs text-sky-600">
Expand All @@ -57,6 +98,27 @@ export const CourtStageTimer = ({ stage }: { stage?: CourtStage }) => {
);
};

export const roundCopy: Record<
CourtAppealRound,
{ description: string; className: string }
> = {
"1": {
description:
"This case outcome has been appealed and is starting a new round of voting.",
className: "text-gray-500 bg-slate-100",
},
"2": {
description:
"This case has been appealed for the second time and is starting a new round of voting.",
className: "text-gray-500 bg-slate-100",
},
"3": {
description:
"This case has been appealed for the third time and is starting its last round of voting. If it is appealed a fourth time it will be moved to global disputes.",
className: "text-orange-800 bg-orange-400",
},
};

export const courtStageCopy: Record<
CourtStage["type"],
{ title: string; description: string; color: string }
Expand All @@ -78,12 +140,12 @@ export const courtStageCopy: Record<
},
appeal: {
title: "Appeal",
description: "Jurors can now appeal the case.",
description: "The case can now be appealed.",
color: "bg-orange-400",
},
reassigned: {
title: "Reassigned",
description: "The case is now reassigned. Winners paid out.",
title: "Settled",
description: "The case is now settled and winners have been paid out.",
color: "bg-gray-400",
},
closed: {
Expand Down
4 changes: 2 additions & 2 deletions components/court/CourtVoteForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { useCourtCommitmentHash } from "lib/state/court/useCourtCommitmentHash";
import { useCourtSalt } from "lib/state/court/useCourtSalt";
import { useCourtVote } from "lib/state/court/useVoteOutcome";
import Image from "next/image";
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
import { AiOutlineEye } from "react-icons/ai";
import { FaArrowRight } from "react-icons/fa";
import { HiOutlineDocumentDownload } from "react-icons/hi";
Expand Down Expand Up @@ -137,7 +137,7 @@ export const CourtVoteForm: React.FC<CourtVoteFormProps> = ({
</p>
<p className="mb-4 text-sm">
This is supplied to the chain instead of the direct outcome
when voting, so that the voted outcome is not known to other
when voting, so that the vote is not known to other
participants. Yet ensures that when its revealed it can be
verified that the committed vote and what was revealed was
correct.
Expand Down
4 changes: 2 additions & 2 deletions components/court/CourtVoteRevealForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export const CourtVoteRevealForm: React.FC<CourtVoteRevealFormProps> = ({
defaultValue: outcomeAssets[0],
});

const { salt, setPhraseSeed } = useCourtSalt({
const { salt, restoreBackup } = useCourtSalt({
marketId: market.marketId,
caseId: caseId,
});
Expand Down Expand Up @@ -110,7 +110,7 @@ export const CourtVoteRevealForm: React.FC<CourtVoteRevealFormProps> = ({
const parsed = IOCourtSaltPhraseStorage.safeParse(JSON.parse(raw));

if (parsed.success) {
const wasSet = await setPhraseSeed(parsed.data);
const wasSet = await restoreBackup(parsed.data);
setHasDroppedFile(wasSet);
}
}
Expand Down
9 changes: 8 additions & 1 deletion components/court/JoinCourtAsJurorButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,12 @@ const JoinCourtAsJurorButton = ({ className }: { className?: string }) => {

<Modal open={isOpen} onClose={() => setIsOpen(false)}>
<Dialog.Panel className="w-full max-w-[462px] rounded-[10px] bg-white p-[30px]">
<h3 className="mb-8">
<h3 className="mb-4">
{connectedParticipant?.type === "Juror"
? "Increase Personal Stake"
: "Become a Juror"}
</h3>

<div className="mt-[20px] flex w-full flex-col items-center gap-8 text-ztg-18-150 font-semibold">
<form
onSubmit={handleSubmit(onSubmit)}
Expand Down Expand Up @@ -180,6 +181,12 @@ const JoinCourtAsJurorButton = ({ className }: { className?: string }) => {
{...register("percentage", { value: "0" })}
/>

{connectedParticipant?.type === "Juror" && (
<div className="relative mb-5 mt-4 w-full rounded-lg bg-provincial-pink p-5 text-sm font-normal">
This will set the new staked amount.
</div>
)}

<div className="my-[4px] mb-5 h-[16px] text-center text-ztg-12-120 text-vermilion">
<>{formState.errors["amount"]?.message}</>
</div>
Expand Down
10 changes: 7 additions & 3 deletions components/court/ManageDelegationsForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@ const ManageDelegationsForm = (props: ManageDelegationsFormProps) => {
percentage: string;
delegates: string[];
}>({
reValidateMode: "onChange",
mode: "onChange",

defaultValues: {
delegates: connectedParticipant?.delegations,
delegates: connectedParticipant?.delegations ?? [],
amount: connectedParticipant?.stake?.div(ZTG).toNumber(),
},
});
Expand Down Expand Up @@ -247,7 +247,11 @@ const ManageDelegationsForm = (props: ManageDelegationsFormProps) => {

<FormTransactionButton
className="w-full max-w-[250px]"
disabled={formState.isValid === false || isLoading}
disabled={
formState.isValid === false ||
isLoading ||
getValues("delegates").length === 0
}
>
Delegate Stake
</FormTransactionButton>
Expand Down
Loading

0 comments on commit 7eddc1c

Please sign in to comment.