Skip to content

Commit d5b2f11

Browse files
authored
Merge pull request #49 from kleros/refactor/evidence-refactors
Refactor/evidence refactors
2 parents 779eb66 + 7b39263 commit d5b2f11

File tree

6 files changed

+77
-108
lines changed

6 files changed

+77
-108
lines changed

contracts/src/CurateV2.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,7 @@ contract CurateV2 is IArbitrableV2 {
392392

393393
/// @dev Submit a request to remove an item from the list. Accepts enough ETH to cover the deposit, reimburses the rest.
394394
/// @param _itemID The ID of the item to remove.
395-
/// @param _evidence A link to evidence using its URI.
395+
/// @param _evidence Stringified evidence object, example: '{"name" : "Justification", "description" : "Description", "fileURI" : "/ipfs/QmWQV5ZFFhEJiW8Lm7ay2zLxC2XS4wx1b2W7FfdrLMyQQc"}'.
396396
function removeItem(bytes32 _itemID, string calldata _evidence) external payable {
397397
Item storage item = items[_itemID];
398398

@@ -430,7 +430,7 @@ contract CurateV2 is IArbitrableV2 {
430430

431431
/// @dev Challenges the request of the item. Accepts enough ETH to cover the deposit, reimburses the rest.
432432
/// @param _itemID The ID of the item which request to challenge.
433-
/// @param _evidence A link to evidence using its URI.
433+
/// @param _evidence Stringified evidence object, example: '{"name" : "Justification", "description" : "Description", "fileURI" : "/ipfs/QmWQV5ZFFhEJiW8Lm7ay2zLxC2XS4wx1b2W7FfdrLMyQQc"}'.
434434
function challengeRequest(bytes32 _itemID, string calldata _evidence) external payable {
435435
Item storage item = items[_itemID];
436436
require(item.status > Status.Registered, "The item must have a pending request.");

web/src/components/ActionButton/Modal/ChallengeItemModal.tsx

Lines changed: 30 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,19 @@ import Buttons from "./Buttons";
55
import DepositRequired from "./DepositRequired";
66
import Info from "./Info";
77
import {
8-
prepareWriteCurateV2,
8+
useCurateV2ChallengeRequest,
99
useCurateV2GetArbitratorExtraData,
1010
useCurateV2RemovalChallengeBaseDeposit,
1111
useCurateV2SubmissionChallengeBaseDeposit,
12+
usePrepareCurateV2ChallengeRequest,
1213
} from "hooks/contracts/generated";
1314
import { useArbitrationCost } from "hooks/useArbitrationCostFromKlerosCore";
14-
import { useAccount, useBalance, usePublicClient, useWalletClient } from "wagmi";
15+
import { useAccount, useBalance, usePublicClient } from "wagmi";
1516
import { wrapWithToast } from "utils/wrapWithToast";
1617
import { IBaseModal } from ".";
1718
import EvidenceUpload, { Evidence } from "./EvidenceUpload";
18-
import { uploadFileToIPFS } from "utils/uploadFileToIPFS";
1919
import Modal from "components/Modal";
20+
import { isUndefined } from "src/utils";
2021

2122
const ReStyledModal = styled(Modal)`
2223
gap: 32px;
@@ -46,7 +47,6 @@ const ChallengeItemModal: React.FC<IChallengeItemModal> = ({
4647
}) => {
4748
const { address } = useAccount();
4849
const publicClient = usePublicClient();
49-
const { data: walletClient } = useWalletClient();
5050

5151
const [isChallengingItem, setIsChallengingItem] = useState(false);
5252
const [isEvidenceUploading, setIsEvidenceUploading] = useState(false);
@@ -81,6 +81,22 @@ const ChallengeItemModal: React.FC<IChallengeItemModal> = ({
8181

8282
const isEvidenceValid = useMemo(() => evidence?.name !== "" && evidence?.description !== "", [evidence]);
8383

84+
const isDisabled = useMemo(() => {
85+
if (!userBalance || !depositRequired || isEvidenceUploading || !isEvidenceValid) return true;
86+
return userBalance?.value < depositRequired;
87+
}, [depositRequired, userBalance, isEvidenceUploading, isEvidenceValid]);
88+
89+
const { config } = usePrepareCurateV2ChallengeRequest({
90+
enabled: !isUndefined(itemId) && !isUndefined(evidence) && !isDisabled,
91+
//@ts-ignore
92+
address: registryAddress,
93+
functionName: "challengeRequest",
94+
args: [itemId as `0x${string}`, JSON.stringify(evidence)],
95+
value: depositRequired,
96+
});
97+
98+
const { writeAsync: challengeRequest } = useCurateV2ChallengeRequest(config);
99+
84100
const isLoading = useMemo(
85101
() =>
86102
isBalanceLoading ||
@@ -101,11 +117,6 @@ const ChallengeItemModal: React.FC<IChallengeItemModal> = ({
101117
]
102118
);
103119

104-
const isDisabled = useMemo(() => {
105-
if (!userBalance || !depositRequired || isEvidenceUploading || !isEvidenceValid) return true;
106-
return userBalance?.value < depositRequired;
107-
}, [depositRequired, userBalance, isEvidenceUploading, isEvidenceValid]);
108-
109120
return (
110121
<ReStyledModal {...{ toggleModal }}>
111122
<Header text={`Challenge ${isItem ? "Item" : "List"}`} />
@@ -117,37 +128,16 @@ const ChallengeItemModal: React.FC<IChallengeItemModal> = ({
117128
toggleModal={toggleModal}
118129
isDisabled={isDisabled || isChallengingItem}
119130
isLoading={isLoading}
120-
callback={async () => {
121-
setIsChallengingItem(true);
122-
123-
const evidenceFile = new File([JSON.stringify(evidence)], "evidence.json", {
124-
type: "application/json",
125-
});
126-
127-
uploadFileToIPFS(evidenceFile)
128-
.then(async (res) => {
129-
if (res.status === 200 && walletClient) {
130-
const response = await res.json();
131-
const fileURI = response["cids"][0];
132-
133-
const { request } = await prepareWriteCurateV2({
134-
//@ts-ignore
135-
address: registryAddress,
136-
functionName: "challengeRequest",
137-
args: [itemId as `0x${string}`, fileURI],
138-
value: depositRequired,
139-
});
140-
141-
wrapWithToast(async () => await walletClient.writeContract(request), publicClient)
142-
.then((res) => {
143-
console.log({ res });
144-
refetch();
145-
toggleModal();
146-
})
147-
.finally(() => setIsChallengingItem(false));
148-
}
149-
})
150-
.catch((err) => console.log(err));
131+
callback={() => {
132+
if (challengeRequest) {
133+
setIsChallengingItem(true);
134+
wrapWithToast(async () => await challengeRequest().then((response) => response.hash), publicClient)
135+
.then(() => {
136+
refetch();
137+
toggleModal();
138+
})
139+
.finally(() => setIsChallengingItem(false));
140+
}
151141
}}
152142
/>
153143
</ReStyledModal>

web/src/components/ActionButton/Modal/RemoveModal.tsx

Lines changed: 29 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,19 @@ import Buttons from "./Buttons";
55
import DepositRequired from "./DepositRequired";
66
import Info from "./Info";
77
import { IBaseModal } from ".";
8-
import { useAccount, useBalance, usePublicClient, useWalletClient } from "wagmi";
8+
import { useAccount, useBalance, usePublicClient } from "wagmi";
99
import {
10-
prepareWriteCurateV2,
1110
useCurateV2GetArbitratorExtraData,
1211
useCurateV2RemovalBaseDeposit,
12+
useCurateV2RemoveItem,
13+
usePrepareCurateV2RemoveItem,
1314
} from "hooks/contracts/generated";
1415
import { useArbitrationCost } from "hooks/useArbitrationCostFromKlerosCore";
1516
import { wrapWithToast } from "utils/wrapWithToast";
1617
import EvidenceUpload, { Evidence } from "./EvidenceUpload";
1718
import { uploadFileToIPFS } from "utils/uploadFileToIPFS";
1819
import Modal from "components/Modal";
20+
import { isUndefined } from "src/utils";
1921

2022
const ReStyledModal = styled(Modal)`
2123
gap: 32px;
@@ -32,11 +34,10 @@ const alertMessage = (isItem: boolean) =>
3234
const RemoveModal: React.FC<IRemoveModal> = ({ toggleModal, isItem, registryAddress, itemId, refetch }) => {
3335
const { address } = useAccount();
3436
const publicClient = usePublicClient();
35-
const { data: walletClient } = useWalletClient();
3637

37-
const [isRemovingItem, setIsRemovingItem] = useState(false);
3838
const [isEvidenceUploading, setIsEvidenceUploading] = useState(false);
3939
const [evidence, setEvidence] = useState<Evidence>();
40+
const [isRemovingItem, setIsRemovingItem] = useState(false);
4041

4142
const { data: userBalance, isLoading: isBalanceLoading } = useBalance({ address });
4243

@@ -59,6 +60,21 @@ const RemoveModal: React.FC<IRemoveModal> = ({ toggleModal, isItem, registryAddr
5960

6061
const isEvidenceValid = useMemo(() => evidence?.name !== "" && evidence?.description !== "", [evidence]);
6162

63+
const isDisabled = useMemo(() => {
64+
if (!userBalance || !depositRequired || isEvidenceUploading || !isEvidenceValid) return true;
65+
return userBalance?.value < depositRequired;
66+
}, [depositRequired, userBalance, isEvidenceUploading, isEvidenceValid]);
67+
68+
const { config } = usePrepareCurateV2RemoveItem({
69+
enabled: !isDisabled || !isUndefined(evidence),
70+
//@ts-ignore
71+
address: registryAddress,
72+
functionName: "removeItem",
73+
args: [itemId as `0x${string}`, JSON.stringify(evidence)],
74+
value: depositRequired,
75+
});
76+
77+
const { writeAsync: removeItem } = useCurateV2RemoveItem(config);
6278
const isLoading = useMemo(
6379
() =>
6480
isBalanceLoading ||
@@ -77,11 +93,6 @@ const RemoveModal: React.FC<IRemoveModal> = ({ toggleModal, isItem, registryAddr
7793
]
7894
);
7995

80-
const isDisabled = useMemo(() => {
81-
if (!userBalance || !depositRequired || isEvidenceUploading || !isEvidenceValid) return true;
82-
return userBalance?.value < depositRequired;
83-
}, [depositRequired, userBalance, isEvidenceUploading, isEvidenceValid]);
84-
8596
return (
8697
<ReStyledModal {...{ toggleModal }}>
8798
<Header text={`Remove ${isItem ? "Item" : "List"}`} />
@@ -94,36 +105,15 @@ const RemoveModal: React.FC<IRemoveModal> = ({ toggleModal, isItem, registryAddr
94105
isDisabled={isDisabled || isRemovingItem}
95106
isLoading={isLoading}
96107
callback={() => {
97-
setIsRemovingItem(true);
98-
99-
const evidenceFile = new File([JSON.stringify(evidence)], "evidence.json", {
100-
type: "application/json",
101-
});
102-
103-
uploadFileToIPFS(evidenceFile)
104-
.then(async (res) => {
105-
if (res.status === 200 && walletClient) {
106-
const response = await res.json();
107-
const fileURI = response["cids"][0];
108-
109-
const { request } = await prepareWriteCurateV2({
110-
//@ts-ignore
111-
address: registryAddress,
112-
functionName: "removeItem",
113-
args: [itemId as `0x${string}`, fileURI],
114-
value: depositRequired,
115-
});
116-
117-
wrapWithToast(async () => await walletClient.writeContract(request), publicClient)
118-
.then((res) => {
119-
console.log({ res });
120-
refetch();
121-
toggleModal();
122-
})
123-
.finally(() => setIsRemovingItem(false));
124-
}
125-
})
126-
.catch((err) => console.log(err));
108+
if (removeItem) {
109+
setIsRemovingItem(true);
110+
wrapWithToast(async () => await removeItem().then((response) => response.hash), publicClient)
111+
.then((res) => {
112+
refetch();
113+
toggleModal();
114+
})
115+
.finally(() => setIsRemovingItem(false));
116+
}
127117
}}
128118
/>
129119
</ReStyledModal>

web/src/components/HistoryDisplay/Party/JustificationDetails.tsx

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import styled from "styled-components";
44
import { getIpfsUrl } from "utils/getIpfsUrl";
55
import AttachmentIcon from "svgs/icons/attachment.svg";
66
import { customScrollbar } from "styles/customScrollbar";
7+
import { Evidence } from "src/graphql/graphql";
78

89
const Container = styled.div`
910
width: 100%;
@@ -32,18 +33,14 @@ const StyledA = styled.a`
3233
}
3334
`;
3435

35-
export type Justification = {
36-
name: string;
37-
description: string;
38-
fileURI?: string;
39-
};
36+
export type Justification = Pick<Evidence, "name" | "description" | "evidence" | "fileURI">;
4037

4138
const JustificationDetails: React.FC<{ justification: Justification }> = ({ justification }) => {
4239
return (
4340
<Container>
44-
<JustificationTitle>{justification.name}</JustificationTitle>
41+
<JustificationTitle>{justification.name ?? "Unable to determine title"}</JustificationTitle>
4542
<DescriptionContainer>
46-
<ReactMarkdown>{justification.description}</ReactMarkdown>
43+
<ReactMarkdown>{justification.description ?? "Unable to determine description"}</ReactMarkdown>
4744
</DescriptionContainer>
4845
{justification?.fileURI && (
4946
<StyledA href={getIpfsUrl(justification.fileURI)}>

web/src/components/HistoryDisplay/Party/JustificationModal.tsx

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ import { mapFromSubgraphStatus } from "components/RegistryCard/StatusBanner";
99

1010
import { EvidencesQuery, RequestDetailsFragment } from "src/graphql/graphql";
1111
import { isUndefined } from "src/utils";
12-
import { getIpfsUrl } from "utils/getIpfsUrl";
13-
import fetchJsonIpfs from "utils/fetchJsonIpfs";
1412
import { useEvidences } from "queries/useEvidences";
1513

1614
import Header from "./Header";
@@ -49,31 +47,22 @@ interface IJustificationModal {
4947
const JustificationModal: React.FC<IJustificationModal> = ({ request, toggleModal, isRemoval }) => {
5048
const { data: evidenceData, isLoading: isLoadingEvidences } = useEvidences(request.externalDisputeID);
5149
const [justification, setJustification] = useState<Justification>();
52-
const [isLoadingJustification, setIsLoadingJustification] = useState(false);
5350

5451
useEffect(() => {
5552
if (isUndefined(evidenceData)) return;
56-
setIsLoadingJustification(true);
5753

58-
const uri = getEvidenceUriForRequest(request, evidenceData.evidences, isRemoval);
54+
const evidence = getEvidenceForRequest(request, evidenceData.evidences, isRemoval);
5955

60-
if (!uri) {
61-
setIsLoadingJustification(false);
62-
return;
56+
if (evidence) {
57+
setJustification(evidence);
6358
}
64-
65-
fetchJsonIpfs(getIpfsUrl(uri))
66-
.then((res) => {
67-
setJustification(res as Justification);
68-
})
69-
.finally(() => setIsLoadingJustification(false));
7059
}, [evidenceData, isRemoval, request]);
7160

7261
return (
7362
<StyledModal {...{ toggleModal }}>
7463
<Header text={isRemoval ? "Removal Requested" : "Request Challenged"} />
7564
<JustificationText>Justification</JustificationText>
76-
{isLoadingEvidences || isLoadingJustification ? (
65+
{isLoadingEvidences ? (
7766
<SkeletonJustificationCard />
7867
) : justification ? (
7968
<JustificationDetails {...{ justification }} />
@@ -100,16 +89,16 @@ const JustificationModal: React.FC<IJustificationModal> = ({ request, toggleModa
10089
* @need this is needed since the removal request might not have the evidence, same for challenge request.
10190
* to get the correct evidence for the request, we match the timestamp of the request and evidence,
10291
* if both are same , it means the evidence was created in the same block as that request and belongs to the request
103-
* @returns the evidence uri for the request if it exists, otherwise null
92+
* @returns the evidence for the request if it exists, otherwise null
10493
*/
105-
const getEvidenceUriForRequest = (
94+
const getEvidenceForRequest = (
10695
request: RequestDetailsFragment,
10796
evidences: EvidencesQuery["evidences"],
10897
isRemoval: boolean
10998
) => {
11099
if (isRemoval) {
111100
if (evidences.length > 0 && evidences[0].timestamp === request.submissionTime) {
112-
return evidences[0].evidence;
101+
return evidences[0];
113102
} else {
114103
return null;
115104
}
@@ -118,8 +107,8 @@ const getEvidenceUriForRequest = (
118107
// in case of challenge either the first or the second one can be the challenge evidence,
119108
// in case of registration challenge, the 1st one is the challenge evidence,
120109
// or if the removal request did not have any justification, the 1st one could be the challenge justification
121-
if (evidences.length > 0 && evidences[0].timestamp === request.challengeTime) return evidences[0].evidence;
122-
if (evidences.length > 1 && evidences[1].timestamp === request.challengeTime) return evidences[1].evidence;
110+
if (evidences.length > 0 && evidences[0].timestamp === request.challengeTime) return evidences[0];
111+
if (evidences.length > 1 && evidences[1].timestamp === request.challengeTime) return evidences[1];
123112

124113
return null;
125114
};

web/src/hooks/queries/useEvidences.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ const evidencesQuery = graphql(`
1010
evidences(where: { evidenceGroup: $evidenceGroupID }, orderBy: timestamp, orderDirection: asc, first: 2) {
1111
evidence
1212
timestamp
13+
name
14+
description
15+
fileURI
1316
}
1417
}
1518
`);

0 commit comments

Comments
 (0)