Skip to content

Commit 8c5e57c

Browse files
committed
fix(web): answer-id-in-dispute-flow
1 parent 3ef595d commit 8c5e57c

File tree

15 files changed

+109
-99
lines changed

15 files changed

+109
-99
lines changed

web/src/components/Verdict/DisputeTimeline.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ const useItems = (disputeDetails?: DisputeDetailsQuery, arbitrable?: `0x${string
105105
const answers = disputeData?.answers;
106106
acc.push({
107107
title: `Jury Decision - Round ${index + 1}`,
108-
party: isOngoing ? "Voting is ongoing" : getVoteChoice(parsedRoundChoice, answers),
108+
party: isOngoing ? "Voting is ongoing" : getVoteChoice(winningChoice, answers),
109109
subtitle: isOngoing
110110
? ""
111111
: `${formatDate(roundTimeline?.[Periods.vote])} / ${
@@ -124,10 +124,10 @@ const useItems = (disputeDetails?: DisputeDetailsQuery, arbitrable?: `0x${string
124124
rightSided: true,
125125
Icon: StyledClosedCircle,
126126
});
127-
} else if (rulingOverride && parsedDisputeFinalRuling !== parsedRoundChoice) {
127+
} else if (rulingOverride && dispute.currentRuling !== winningChoice) {
128128
acc.push({
129129
title: "Won by Appeal",
130-
party: getVoteChoice(parsedDisputeFinalRuling, answers),
130+
party: getVoteChoice(dispute.currentRuling, answers),
131131
subtitle: formatDate(roundTimeline?.[Periods.appeal]),
132132
rightSided: true,
133133
Icon: ClosedCaseIcon,

web/src/hooks/queries/useClassicAppealQuery.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,12 @@ const classicAppealQuery = graphql(`
2525
localRounds {
2626
... on ClassicRound {
2727
winningChoice
28-
paidFees
28+
answers {
29+
answerId
30+
count
31+
paidFee
32+
funded
33+
}
2934
fundedChoices
3035
appealFeesDispersed
3136
totalFeeDispersed

web/src/hooks/useClassicAppealContext.tsx

+30-18
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,21 @@ import { getLocalRounds } from "utils/getLocalRounds";
1111
import { useAppealCost } from "queries/useAppealCost";
1212
import { useClassicAppealQuery, ClassicAppealQuery } from "queries/useClassicAppealQuery";
1313
import { useDisputeKitClassicMultipliers } from "queries/useDisputeKitClassicMultipliers";
14+
import { Answer, DisputeDetails } from "@kleros/kleros-sdk";
1415

16+
type Option = Answer & { paidFee?: string; funded?: boolean };
1517
interface ICountdownContext {
1618
loserSideCountdown?: number;
1719
winnerSideCountdown?: number;
1820
}
21+
1922
const CountdownContext = createContext<ICountdownContext>({});
2023

21-
const OptionsContext = createContext<string[] | undefined>(undefined);
24+
const OptionsContext = createContext<Option[] | undefined>(undefined);
2225

2326
interface ISelectedOptionContext {
24-
selectedOption: number | undefined;
25-
setSelectedOption: (arg0: number) => void;
27+
selectedOption: Option | undefined;
28+
setSelectedOption: (arg0: Option) => void;
2629
}
2730
const SelectedOptionContext = createContext<ISelectedOptionContext>({
2831
selectedOption: undefined,
@@ -32,14 +35,13 @@ const SelectedOptionContext = createContext<ISelectedOptionContext>({
3235

3336
interface IFundingContext {
3437
winningChoice: string | undefined;
35-
paidFees: bigint[] | undefined;
3638
loserRequiredFunding: bigint | undefined;
3739
winnerRequiredFunding: bigint | undefined;
3840
fundedChoices: string[] | undefined;
3941
}
42+
4043
const FundingContext = createContext<IFundingContext>({
4144
winningChoice: undefined,
42-
paidFees: undefined,
4345
loserRequiredFunding: undefined,
4446
winnerRequiredFunding: undefined,
4547
fundedChoices: undefined,
@@ -51,17 +53,16 @@ export const ClassicAppealProvider: React.FC<{
5153
const { id } = useParams();
5254
const { data } = useClassicAppealQuery(id);
5355
const dispute = data?.dispute;
54-
const paidFees = getPaidFees(data?.dispute);
5556
const winningChoice = getWinningChoice(data?.dispute);
5657
const { data: appealCost } = useAppealCost(id);
5758
const arbitrable = data?.dispute?.arbitrated.id;
58-
const { data: disputeDetails } = usePopulatedDisputeData(id, arbitrable);
59+
const { data: disputeDetails } = usePopulatedDisputeData(id, arbitrable as `0x${string}`);
5960
const { data: multipliers } = useDisputeKitClassicMultipliers();
60-
const options = ["Refuse to Arbitrate"].concat(
61-
disputeDetails?.answers?.map((answer: { title: string; description: string }) => {
62-
return answer.title;
63-
})
64-
);
61+
62+
const [selectedOption, setSelectedOption] = useState<Option>();
63+
64+
const options = useMemo(() => getOptions(disputeDetails, data?.dispute), [disputeDetails, data]);
65+
6566
const loserSideCountdown = useLoserSideCountdown(
6667
dispute?.lastPeriodChange,
6768
dispute?.court.timesPerPeriod[Periods.appeal],
@@ -81,7 +82,6 @@ export const ClassicAppealProvider: React.FC<{
8182
[appealCost, multipliers]
8283
);
8384
const fundedChoices = getFundedChoices(data?.dispute);
84-
const [selectedOption, setSelectedOption] = useState<number | undefined>();
8585

8686
return (
8787
<CountdownContext.Provider
@@ -94,12 +94,11 @@ export const ClassicAppealProvider: React.FC<{
9494
value={useMemo(
9595
() => ({
9696
winningChoice,
97-
paidFees,
9897
loserRequiredFunding,
9998
winnerRequiredFunding,
10099
fundedChoices,
101100
}),
102-
[winningChoice, paidFees, loserRequiredFunding, winnerRequiredFunding, fundedChoices]
101+
[winningChoice, loserRequiredFunding, winnerRequiredFunding, fundedChoices]
103102
)}
104103
>
105104
<OptionsContext.Provider value={options}>{children}</OptionsContext.Provider>
@@ -126,9 +125,22 @@ const getCurrentLocalRound = (dispute?: ClassicAppealQuery["dispute"]) => {
126125
return getLocalRounds(dispute.disputeKitDispute)[adjustedRoundIndex];
127126
};
128127

129-
const getPaidFees = (dispute?: ClassicAppealQuery["dispute"]) => {
130-
const currentLocalRound = getCurrentLocalRound(dispute);
131-
return currentLocalRound?.paidFees.map((amount: string) => BigInt(amount));
128+
const getOptions = (dispute?: DisputeDetails, classicDispute?: ClassicAppealQuery["dispute"]) => {
129+
if (!dispute) return [];
130+
const currentLocalRound = getCurrentLocalRound(classicDispute);
131+
const classicAnswers = currentLocalRound?.answers;
132+
133+
const options = dispute.answers.map((answer) => {
134+
const classicAnswer = classicAnswers?.find((classicAnswer) => BigInt(classicAnswer.answerId) == BigInt(answer.id));
135+
// converting hexadecimal id to stringified bigint to match id fomr subgraph
136+
return {
137+
...answer,
138+
id: BigInt(answer.id).toString(),
139+
paidFee: classicAnswer?.paidFee ?? "0",
140+
funded: classicAnswer?.funded ?? false,
141+
};
142+
});
143+
return options;
132144
};
133145

134146
const getFundedChoices = (dispute?: ClassicAppealQuery["dispute"]) => {

web/src/pages/Cases/CaseDetails/Appeal/AppealHistory.tsx

+7-7
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ interface IAppealHistory {
2525

2626
const AppealHistory: React.FC<IAppealHistory> = ({ isAppealMiniGuideOpen, toggleAppealMiniGuide }) => {
2727
const options = useOptionsContext();
28-
const { winningChoice, paidFees, fundedChoices } = useFundingContext();
28+
const { winningChoice, fundedChoices } = useFundingContext();
2929

3030
return options && options.length > 2 ? (
3131
<div>
@@ -38,13 +38,13 @@ const AppealHistory: React.FC<IAppealHistory> = ({ isAppealMiniGuideOpen, toggle
3838
/>
3939
</AppealHeader>
4040
<OptionsContainer>
41-
{options.map((option, index) => (
41+
{options?.map((option) => (
4242
<OptionCard
43-
key={option + index}
44-
text={option}
45-
winner={index.toString() === winningChoice}
46-
funding={BigInt(paidFees?.[index] ?? "0")}
47-
required={fundedChoices?.includes(index.toString()) ? BigInt(paidFees?.[index] ?? "0") : undefined}
43+
key={option.id}
44+
text={option.title}
45+
winner={option.id === winningChoice}
46+
funding={BigInt(option.paidFee ?? 0)}
47+
required={fundedChoices?.includes(option.id) ? BigInt(option.paidFee ?? 0) : undefined}
4848
canBeSelected={false}
4949
/>
5050
))}

web/src/pages/Cases/CaseDetails/Appeal/Classic/Fund.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ const useFundAppeal = (parsedAmount, insufficientBalance) => {
7373
query: {
7474
enabled: !isUndefined(id) && !isUndefined(selectedOption) && !insufficientBalance,
7575
},
76-
args: [BigInt(id ?? 0), BigInt(selectedOption ?? 0)],
76+
args: [BigInt(id ?? 0), BigInt(selectedOption?.id ?? 0)],
7777
value: parsedAmount,
7878
});
7979

web/src/pages/Cases/CaseDetails/Appeal/Classic/Options/StageOne.tsx

+11-12
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ interface IStageOne {
2929
}
3030

3131
const StageOne: React.FC<IStageOne> = ({ setAmount }) => {
32-
const { paidFees, winningChoice, loserRequiredFunding, winnerRequiredFunding, fundedChoices } = useFundingContext();
32+
const { winningChoice, loserRequiredFunding, winnerRequiredFunding } = useFundingContext();
3333
const options = useOptionsContext();
3434
const { loserSideCountdown } = useCountdownContext();
3535
const { selectedOption, setSelectedOption } = useSelectedOptionContext();
@@ -39,22 +39,21 @@ const StageOne: React.FC<IStageOne> = ({ setAmount }) => {
3939
<StageExplainer countdown={loserSideCountdown} stage={1} />
4040
<label> Which option do you want to fund? </label>
4141
<OptionsContainer>
42-
{!isUndefined(paidFees) &&
43-
!isUndefined(winnerRequiredFunding) &&
42+
{!isUndefined(winnerRequiredFunding) &&
4443
!isUndefined(loserRequiredFunding) &&
45-
options?.map((answer: string, i: number) => {
46-
const requiredFunding = i.toString() === winningChoice ? winnerRequiredFunding : loserRequiredFunding;
44+
options?.map((option) => {
45+
const requiredFunding = option.id === winningChoice ? winnerRequiredFunding : loserRequiredFunding;
4746
return (
4847
<OptionCard
49-
key={answer}
50-
text={answer}
51-
selected={i === selectedOption}
52-
winner={i.toString() === winningChoice}
53-
funding={paidFees[i] ? BigInt(paidFees[i]) : 0n}
48+
key={option.id}
49+
text={option.title}
50+
selected={option.id === selectedOption?.id}
51+
winner={option.id === winningChoice}
52+
funding={BigInt(option.paidFee ?? 0)}
5453
required={requiredFunding}
55-
canBeSelected={!fundedChoices?.includes(i.toString())}
54+
canBeSelected={!option?.funded}
5655
onClick={() => {
57-
setSelectedOption(i);
56+
setSelectedOption(option);
5857
setAmount(formatUnitsWei(requiredFunding));
5958
}}
6059
/>

web/src/pages/Cases/CaseDetails/Appeal/Classic/Options/StageTwo.tsx

+12-10
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useEffect } from "react";
1+
import React, { useEffect, useMemo } from "react";
22
import styled from "styled-components";
33

44
import Skeleton from "react-loading-skeleton";
@@ -31,31 +31,33 @@ interface IStageTwo {
3131
}
3232

3333
const StageTwo: React.FC<IStageTwo> = ({ setAmount }) => {
34-
const { paidFees, winningChoice, winnerRequiredFunding, fundedChoices } = useFundingContext();
34+
const { winningChoice, winnerRequiredFunding, fundedChoices } = useFundingContext();
3535
const { winnerSideCountdown } = useCountdownContext();
3636
const options = useOptionsContext();
3737
const { selectedOption, setSelectedOption } = useSelectedOptionContext();
38+
const choice = useMemo(() => options?.find((option) => option.id === winningChoice), [options, winningChoice]);
39+
3840
useEffect(() => {
39-
if (!isUndefined(winningChoice)) setSelectedOption(parseInt(winningChoice));
41+
if (!isUndefined(choice)) setSelectedOption(choice);
4042
if (!isUndefined(winnerRequiredFunding)) setAmount(formatUnitsWei(winnerRequiredFunding));
41-
}, [winnerRequiredFunding, winningChoice]);
43+
}, [winnerRequiredFunding, choice]);
4244

4345
return (
4446
<Container>
45-
{!isUndefined(winningChoice) && !isUndefined(fundedChoices) && !isUndefined(paidFees) ? (
47+
{!isUndefined(choice) && !isUndefined(fundedChoices) ? (
4648
<>
47-
{fundedChoices.length > 0 && !fundedChoices.includes(winningChoice) ? (
49+
{fundedChoices.length > 0 && !choice.funded ? (
4850
<>
4951
<StageExplainer stage={2} countdown={winnerSideCountdown} />
5052
<OptionsContainer>
5153
<OptionCard
52-
text={options![winningChoice!]}
53-
selected={parseInt(winningChoice) === selectedOption}
54+
text={choice.title}
55+
selected={choice.id === selectedOption?.id}
5456
winner={true}
55-
funding={paidFees![winningChoice!] ? BigInt(paidFees![winningChoice!]) : 0n}
57+
funding={BigInt(choice.paidFee ?? 0)}
5658
required={winnerRequiredFunding!}
5759
canBeSelected={false}
58-
onClick={() => setSelectedOption(parseInt(winningChoice!, 10))}
60+
onClick={() => setSelectedOption(choice)}
5961
/>
6062
</OptionsContainer>
6163
</>

web/src/pages/Cases/CaseDetails/Appeal/Classic/StageExplainer.tsx

+3-12
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
import React from "react";
22
import styled from "styled-components";
33

4-
import Skeleton from "react-loading-skeleton";
5-
64
import { Box } from "@kleros/ui-components-library";
75

86
import HourglassIcon from "svgs/icons/hourglass.svg";
97

10-
import { useFundingContext, useOptionsContext } from "hooks/useClassicAppealContext";
8+
import { useOptionsContext } from "hooks/useClassicAppealContext";
119
import { secondsToDayHourMinute } from "utils/date";
1210
import { isUndefined } from "utils/index";
1311

@@ -56,7 +54,6 @@ const StageOneExplanation: React.FC = () => (
5654
);
5755

5856
const StageTwoExplanation: React.FC = () => {
59-
const { fundedChoices } = useFundingContext();
6057
const options = useOptionsContext();
6158
return (
6259
<div>
@@ -69,14 +66,8 @@ const StageTwoExplanation: React.FC = () => {
6966
</label>
7067
<label>
7168
{" "}
72-
Following choice was funded in the stage 1 :{" "}
73-
<small>
74-
{!isUndefined(fundedChoices) && !isUndefined(options)
75-
? fundedChoices.map((choice) =>
76-
isUndefined(options[choice]) ? <Skeleton key={choice} width={50} height={18} /> : options[choice]
77-
)
78-
: null}
79-
</small>
69+
Following choices were funded in the stage 1 :{" "}
70+
<small>{options?.map((option) => (option?.funded ? option.title : null))}</small>
8071
</label>
8172
</div>
8273
);

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

+3-4
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React, { useState } from "react";
22

33
import AppealIcon from "svgs/icons/appeal.svg";
44

5-
import { useOptionsContext, useSelectedOptionContext } from "hooks/useClassicAppealContext";
5+
import { useSelectedOptionContext } from "hooks/useClassicAppealContext";
66
import { isUndefined } from "utils/index";
77

88
import HowItWorks from "components/HowItWorks";
@@ -23,7 +23,6 @@ const Classic: React.FC<IClassic> = ({ isAppealMiniGuideOpen, toggleAppealMiniGu
2323
const [isPopupOpen, setIsPopupOpen] = useState(false);
2424
const [amount, setAmount] = useState("");
2525
const { selectedOption } = useSelectedOptionContext();
26-
const options = useOptionsContext();
2726

2827
return (
2928
<>
@@ -34,7 +33,7 @@ const Classic: React.FC<IClassic> = ({ isAppealMiniGuideOpen, toggleAppealMiniGu
3433
popupType={PopupType.APPEAL}
3534
setIsOpen={setIsPopupOpen}
3635
setAmount={setAmount}
37-
option={!isUndefined(options) && !isUndefined(selectedOption) ? options[selectedOption] : ""}
36+
option={!isUndefined(selectedOption) ? selectedOption.title : ""}
3837
amount={amount}
3938
/>
4039
)}
@@ -48,7 +47,7 @@ const Classic: React.FC<IClassic> = ({ isAppealMiniGuideOpen, toggleAppealMiniGu
4847
</AppealHeader>
4948
<label> The jury decision is appealed when two options are fully funded. </label>
5049
<Options setAmount={setAmount} />
51-
<Fund amount={amount} setAmount={setAmount} setIsOpen={setIsPopupOpen} />
50+
<Fund amount={amount as `${number}`} setAmount={setAmount} setIsOpen={setIsPopupOpen} />
5251
</>
5352
);
5453
};

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ const Commit: React.FC<ICommit> = ({ arbitrable, voteIDs, setIsOpen, refetch })
4444
const [_, setSalt] = useLocalStorage(saltKey);
4545

4646
const handleCommit = useCallback(
47-
async (choice: number) => {
47+
async (choice: bigint) => {
4848
const message = { message: saltKey };
4949
const rawSalt = !isUndefined(signingAccount)
5050
? await signingAccount.signMessage(message)
@@ -56,12 +56,12 @@ const Commit: React.FC<ICommit> = ({ arbitrable, voteIDs, setIsOpen, refetch })
5656
if (isUndefined(rawSalt)) return;
5757

5858
const salt = keccak256(rawSalt);
59-
setSalt(JSON.stringify({ salt, choice }));
59+
setSalt(JSON.stringify({ salt, choice: choice.toString() }));
6060
const commit = keccak256(encodePacked(["uint256", "uint256"], [BigInt(choice), BigInt(salt)]));
6161
const { request } = await simulateDisputeKitClassicCastCommit(wagmiConfig, {
6262
args: [parsedDisputeID, parsedVoteIDs, commit],
6363
});
64-
if (walletClient) {
64+
if (walletClient && publicClient) {
6565
await wrapWithToast(async () => await walletClient.writeContract(request), publicClient).then(({ status }) => {
6666
setIsOpen(status);
6767
});

0 commit comments

Comments
 (0)