Skip to content

Commit f988e09

Browse files
authored
Merge branch 'dev' into feat/cases-by-court-chart
2 parents 2c5d1fd + 53249a7 commit f988e09

File tree

16 files changed

+298
-101
lines changed

16 files changed

+298
-101
lines changed

contracts/src/arbitration/evidence/EvidenceModule.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ contract EvidenceModule is IEvidence, Initializable, UUPSProxiable {
6464

6565
/// @dev Submits evidence for a dispute.
6666
/// @param _externalDisputeID Unique identifier for this dispute outside Kleros. It's the submitter responsability to submit the right evidence group ID.
67-
/// @param _evidence IPFS path to evidence, example: '/ipfs/Qmarwkf7C9RuzDEJNnarT3WZ7kem5bk8DZAzx78acJjMFH/evidence.json'.
67+
/// @param _evidence Stringified evidence object, example: '{"name" : "Justification", "description" : "Description", "fileURI" : "/ipfs/QmWQV5ZFFhEJiW8Lm7ay2zLxC2XS4wx1b2W7FfdrLMyQQc"}'.
6868
function submitEvidence(uint256 _externalDisputeID, string calldata _evidence) external {
6969
emit Evidence(_externalDisputeID, msg.sender, _evidence);
7070
}

contracts/src/arbitration/evidence/ModeratedEvidenceModule.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ contract ModeratedEvidenceModule is IArbitrableV2 {
8484
/// @param _arbitrator The arbitrator of the contract.
8585
/// @param _externalDisputeID Unique identifier for this dispute outside Kleros. It's the submitter responsability to submit the right evidence group ID.
8686
/// @param _party The address of the party submiting the evidence. Note that 0x0 refers to evidence not submitted by any party.
87-
/// @param _evidence IPFS path to evidence, example: '/ipfs/Qmarwkf7C9RuzDEJNnarT3WZ7kem5bk8DZAzx78acJjMFH/evidence.json'
87+
/// @param _evidence Stringified evidence object, example: '{"name" : "Justification", "description" : "Description", "fileURI" : "/ipfs/QmWQV5ZFFhEJiW8Lm7ay2zLxC2XS4wx1b2W7FfdrLMyQQc"}'.
8888
event ModeratedEvidence(
8989
IArbitratorV2 indexed _arbitrator,
9090
uint256 indexed _externalDisputeID,
@@ -201,7 +201,7 @@ contract ModeratedEvidenceModule is IArbitrableV2 {
201201

202202
/// @dev Submits evidence.
203203
/// @param _evidenceGroupID Unique identifier of the evidence group the evidence belongs to. It's the submitter responsability to submit the right evidence group ID.
204-
/// @param _evidence IPFS path to evidence, example: '/ipfs/Qmarwkf7C9RuzDEJNnarT3WZ7kem5bk8DZAzx78acJjMFH/evidence.json'.
204+
/// @param _evidence Stringified evidence object, example: '{"name" : "Justification", "description" : "Description", "fileURI" : "/ipfs/QmWQV5ZFFhEJiW8Lm7ay2zLxC2XS4wx1b2W7FfdrLMyQQc"}'.
205205
function submitEvidence(uint256 _evidenceGroupID, string calldata _evidence) external payable {
206206
// Optimization opportunity: map evidenceID to an incremental index that can be safely assumed to be less than a small uint.
207207
bytes32 evidenceID = keccak256(abi.encodePacked(_evidenceGroupID, _evidence));

contracts/src/arbitration/interfaces/IEvidence.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@ interface IEvidence {
77
/// @dev To be raised when evidence is submitted. Should point to the resource (evidences are not to be stored on chain due to gas considerations).
88
/// @param _externalDisputeID Unique identifier for this dispute outside Kleros. It's the submitter responsability to submit the right external dispute ID.
99
/// @param _party The address of the party submiting the evidence. Note that 0x0 refers to evidence not submitted by any party.
10-
/// @param _evidence IPFS path to evidence, example: '/ipfs/Qmarwkf7C9RuzDEJNnarT3WZ7kem5bk8DZAzx78acJjMFH/evidence.json'
10+
/// @param _evidence Stringified evidence object, example: '{"name" : "Justification", "description" : "Description", "fileURI" : "/ipfs/QmWQV5ZFFhEJiW8Lm7ay2zLxC2XS4wx1b2W7FfdrLMyQQc"}'.
1111
event Evidence(uint256 indexed _externalDisputeID, address indexed _party, string _evidence);
1212
}

subgraph/core-neo/subgraph.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
specVersion: 0.0.4
22
schema:
33
file: ./schema.graphql
4+
features:
5+
- fullTextSearch
6+
47
dataSources:
58
- kind: ethereum
69
name: KlerosCore

subgraph/core-university/subgraph.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
specVersion: 0.0.4
22
schema:
33
file: ./schema.graphql
4+
features:
5+
- fullTextSearch
6+
47
dataSources:
58
- kind: ethereum
69
name: KlerosCore

subgraph/core/schema.graphql

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,14 @@ interface Evidence {
5252
id: ID!
5353
evidence: String!
5454
evidenceGroup: EvidenceGroup!
55+
evidenceIndex: String!
5556
sender: User!
57+
senderAddress: String!
5658
timestamp: BigInt!
59+
name: String
60+
description: String
61+
fileURI: String
62+
fileTypeExtension: String
5763
}
5864

5965
############
@@ -292,12 +298,18 @@ type ClassicEvidenceGroup implements EvidenceGroup @entity {
292298
nextEvidenceIndex: BigInt!
293299
}
294300

295-
type ClassicEvidence implements Evidence @entity {
301+
type ClassicEvidence implements Evidence @entity(immutable: true) {
296302
id: ID! # classicEvidenceGroup.id-nextEvidenceIndex
297303
evidence: String!
298304
evidenceGroup: EvidenceGroup!
305+
evidenceIndex: String!
299306
sender: User!
307+
senderAddress: String!
300308
timestamp: BigInt!
309+
name: String
310+
description: String
311+
fileURI: String
312+
fileTypeExtension: String
301313
}
302314

303315
type ClassicContribution implements Contribution @entity {
@@ -311,3 +323,11 @@ type ClassicContribution implements Contribution @entity {
311323
choice: BigInt!
312324
rewardWithdrawn: Boolean!
313325
}
326+
327+
type _Schema_
328+
@fulltext(
329+
name: "evidenceSearch"
330+
language: en
331+
algorithm: rank
332+
include: [{ entity: "ClassicEvidence", fields: [{ name: "name" }, { name: "description" },{ name: "senderAddress"},{ name: "evidenceIndex"}] }]
333+
)

subgraph/core/src/EvidenceModule.ts

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,63 @@
1+
import { json, JSONValueKind, log } from "@graphprotocol/graph-ts";
12
import { Evidence as EvidenceEvent } from "../generated/EvidenceModule/EvidenceModule";
23
import { ClassicEvidence } from "../generated/schema";
34
import { ensureClassicEvidenceGroup } from "./entities/ClassicEvidenceGroup";
45
import { ensureUser } from "./entities/User";
56
import { ONE } from "./utils";
7+
import { JSONValueToMaybeString } from "../../utils";
68

79
export function handleEvidenceEvent(event: EvidenceEvent): void {
810
const evidenceGroupID = event.params._externalDisputeID.toString();
911
const evidenceGroup = ensureClassicEvidenceGroup(evidenceGroupID);
1012
const evidenceIndex = evidenceGroup.nextEvidenceIndex;
1113
evidenceGroup.nextEvidenceIndex = evidenceGroup.nextEvidenceIndex.plus(ONE);
1214
evidenceGroup.save();
13-
const evidence = new ClassicEvidence(`${evidenceGroupID}-${evidenceIndex.toString()}`);
15+
const evidenceId = `${evidenceGroupID}-${evidenceIndex.toString()}`;
16+
const evidence = new ClassicEvidence(evidenceId);
17+
evidence.evidenceIndex = evidenceIndex.plus(ONE).toString();
1418
const userId = event.params._party.toHexString();
1519
evidence.timestamp = event.block.timestamp;
1620
evidence.evidence = event.params._evidence;
1721
evidence.evidenceGroup = evidenceGroupID.toString();
1822
evidence.sender = userId;
23+
evidence.senderAddress = userId;
1924
ensureUser(userId);
25+
26+
let jsonObjValueAndSuccess = json.try_fromString(event.params._evidence);
27+
if (!jsonObjValueAndSuccess.isOk || jsonObjValueAndSuccess.isError) {
28+
log.error(`Error getting json object for evidenceId {}`, [evidenceId]);
29+
evidence.save();
30+
return;
31+
}
32+
33+
if (jsonObjValueAndSuccess.value.isNull() || jsonObjValueAndSuccess.value.kind !== JSONValueKind.OBJECT) {
34+
log.error(`Encountered invalid parsed value for evidenceId {}`, [evidenceId]);
35+
evidence.save();
36+
return;
37+
}
38+
39+
let jsonObj = jsonObjValueAndSuccess.value.toObject();
40+
if (!jsonObj) {
41+
log.error(`Error converting json object for evidenceId {}`, [evidenceId]);
42+
evidence.save();
43+
return;
44+
}
45+
46+
let name = jsonObj.get("name");
47+
let description = jsonObj.get("description");
48+
let fileURI = jsonObj.get("fileURI");
49+
let fileTypeExtension = jsonObj.get("fileTypeExtension");
50+
51+
evidence.name = JSONValueToMaybeString(name);
52+
evidence.description = JSONValueToMaybeString(description);
53+
54+
if (fileURI) {
55+
evidence.fileURI = JSONValueToMaybeString(fileURI);
56+
}
57+
58+
if (fileTypeExtension) {
59+
evidence.fileTypeExtension = JSONValueToMaybeString(fileTypeExtension);
60+
}
61+
2062
evidence.save();
2163
}

subgraph/core/subgraph.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
specVersion: 0.0.4
22
schema:
33
file: ./schema.graphql
4+
features:
5+
- fullTextSearch
6+
47
dataSources:
58
- kind: ethereum
69
name: KlerosCore

subgraph/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@kleros/kleros-v2-subgraph",
3-
"version": "0.5.1",
3+
"version": "0.7.0",
44
"license": "MIT",
55
"scripts": {
66
"update:core:arbitrum-sepolia-devnet": "./scripts/update.sh arbitrumSepoliaDevnet arbitrum-sepolia core/subgraph.yaml",

subgraph/utils/index.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { JSONValue, JSONValueKind } from "@graphprotocol/graph-ts";
2+
3+
export function JSONValueToMaybeString(value: JSONValue | null, _default: string = "-"): string {
4+
// Subgraph considers an empty string to be null and
5+
// the handler crashes when attempting to save the entity.
6+
// This is a security vulnerability because an adversary
7+
// could manually craft an item with missing columns
8+
// and the item would not show up in the UI, passing
9+
// the challenge period unoticed.
10+
//
11+
// We fix this by setting the field manually to a hifen.
12+
if (value == null || value.isNull()) {
13+
return "-";
14+
}
15+
16+
switch (value.kind) {
17+
case JSONValueKind.BOOL:
18+
return value.toBool() == true ? "true" : "false";
19+
case JSONValueKind.STRING:
20+
return value.toString();
21+
case JSONValueKind.NUMBER:
22+
return value.toBigInt().toHexString();
23+
default:
24+
return _default;
25+
}
26+
}

0 commit comments

Comments
 (0)