Skip to content

Commit 9382b7f

Browse files
Merge branch 'dev' into feat/atlas-siwe
2 parents 1ae4047 + 1f37740 commit 9382b7f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1264
-323
lines changed

subgraph/core/schema.graphql

+5-2
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,10 @@ type User @entity {
7979
resolvedDisputes: [Dispute!]!
8080
totalResolvedDisputes: BigInt!
8181
totalDisputes: BigInt!
82-
totalCoherent: BigInt!
83-
coherenceScore: BigInt!
8482
totalAppealingDisputes: BigInt!
83+
totalCoherentVotes: BigInt!
84+
totalResolvedVotes: BigInt!
85+
coherenceScore: BigInt!
8586
votes: [Vote!]! @derivedFrom(field: "juror")
8687
contributions: [Contribution!]! @derivedFrom(field: "contributor")
8788
evidences: [Evidence!]! @derivedFrom(field: "sender")
@@ -142,9 +143,11 @@ type Court @entity {
142143
numberClosedDisputes: BigInt!
143144
numberVotingDisputes: BigInt!
144145
numberAppealingDisputes: BigInt!
146+
numberVotes: BigInt!
145147
stakedJurors: [JurorTokensPerCourt!]! @derivedFrom(field: "court")
146148
numberStakedJurors: BigInt!
147149
stake: BigInt!
150+
effectiveStake: BigInt!
148151
delayedStake: BigInt!
149152
paidETH: BigInt!
150153
paidPNK: BigInt!

subgraph/core/src/KlerosCore.ts

+50-3
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ import { createDisputeKitFromEvent, filterSupportedDisputeKits } from "./entitie
1919
import { createDisputeFromEvent } from "./entities/Dispute";
2020
import { createRoundFromRoundInfo, updateRoundTimeline } from "./entities/Round";
2121
import { updateCases, updateCasesAppealing, updateCasesRuled, updateCasesVoting } from "./datapoint";
22-
import { addUserActiveDispute, ensureUser } from "./entities/User";
22+
import { addUserActiveDispute, computeCoherenceScore, ensureUser } from "./entities/User";
2323
import { updateJurorStake } from "./entities/JurorTokensPerCourt";
2424
import { createDrawFromEvent } from "./entities/Draw";
2525
import { updateTokenAndEthShiftFromEvent } from "./entities/TokenAndEthShift";
2626
import { updateArbitrableCases } from "./entities/Arbitrable";
27-
import { Court, Dispute, Round, User } from "../generated/schema";
27+
import { ClassicVote, Court, Dispute, Draw, Round, User } from "../generated/schema";
2828
import { BigInt } from "@graphprotocol/graph-ts";
2929
import { updatePenalty } from "./entities/Penalty";
3030
import { ensureFeeToken } from "./entities/FeeToken";
@@ -75,9 +75,12 @@ export function handleDisputeCreation(event: DisputeCreation): void {
7575
const court = Court.load(courtID);
7676
if (!court) return;
7777
court.numberDisputes = court.numberDisputes.plus(ONE);
78+
79+
const roundInfo = contract.getRoundInfo(disputeID, ZERO);
80+
court.numberVotes = court.numberVotes.plus(roundInfo.nbVotes);
81+
7882
court.save();
7983
createDisputeFromEvent(event);
80-
const roundInfo = contract.getRoundInfo(disputeID, ZERO);
8184
createRoundFromRoundInfo(KlerosCore.bind(event.address), disputeID, ZERO, roundInfo);
8285
const arbitrable = event.params._arbitrable.toHexString();
8386
updateArbitrableCases(arbitrable, ONE);
@@ -124,6 +127,41 @@ export function handleNewPeriod(event: NewPeriod): void {
124127
dispute.currentRuling = currentRulingInfo.getRuling();
125128
dispute.overridden = currentRulingInfo.getOverridden();
126129
dispute.tied = currentRulingInfo.getTied();
130+
131+
const rounds = dispute.rounds.load();
132+
for (let i = 0; i < rounds.length; i++) {
133+
const round = Round.load(rounds[i].id);
134+
if (!round) continue;
135+
136+
const draws = round.drawnJurors.load();
137+
// Iterate over all draws in the round
138+
for (let j = 0; j < draws.length; j++) {
139+
const draw = Draw.load(draws[j].id);
140+
if (!draw) continue;
141+
142+
// Since this is a ClassicVote entity, this will only work for the Classic DisputeKit (which has ID "1").
143+
const vote = ClassicVote.load(`${round.disputeKit}-${draw.id}`);
144+
145+
if (!vote) continue;
146+
147+
const juror = ensureUser(draw.juror);
148+
juror.totalResolvedVotes = juror.totalResolvedVotes.plus(ONE);
149+
150+
if (vote.choice === null) continue;
151+
152+
// Check if the vote choice matches the final ruling
153+
if (vote.choice!.equals(dispute.currentRuling)) {
154+
juror.totalCoherentVotes = juror.totalCoherentVotes.plus(ONE);
155+
}
156+
157+
// Recalculate coherenceScore
158+
if (juror.totalResolvedVotes.gt(ZERO)) {
159+
juror.coherenceScore = computeCoherenceScore(juror.totalCoherentVotes, juror.totalResolvedVotes);
160+
}
161+
162+
juror.save();
163+
}
164+
}
127165
}
128166

129167
dispute.period = newPeriod;
@@ -164,6 +202,15 @@ export function handleAppealDecision(event: AppealDecision): void {
164202
dispute.currentRound = roundID;
165203
dispute.save();
166204
const roundInfo = contract.getRoundInfo(disputeID, newRoundIndex);
205+
206+
const disputeStorage = contract.disputes(disputeID);
207+
const courtID = disputeStorage.value0.toString();
208+
const court = Court.load(courtID);
209+
if (!court) return;
210+
211+
court.numberVotes = court.numberVotes.plus(roundInfo.nbVotes);
212+
court.save();
213+
167214
createRoundFromRoundInfo(KlerosCore.bind(event.address), disputeID, newRoundIndex, roundInfo);
168215
}
169216

subgraph/core/src/entities/Court.ts

+31
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,35 @@ import { CourtCreated } from "../../generated/KlerosCore/KlerosCore";
33
import { Court } from "../../generated/schema";
44
import { ZERO } from "../utils";
55

6+
// This function calculates the "effective" stake, which is the specific stake
7+
// of the current court + the specific stake of all of its children courts
8+
export function updateEffectiveStake(courtID: string): void {
9+
let court = Court.load(courtID);
10+
if (!court) return;
11+
12+
while (court) {
13+
let totalStake = court.stake;
14+
15+
const childrenCourts = court.children.load();
16+
17+
for (let i = 0; i < childrenCourts.length; i++) {
18+
const childCourt = Court.load(childrenCourts[i].id);
19+
if (childCourt) {
20+
totalStake = totalStake.plus(childCourt.effectiveStake);
21+
}
22+
}
23+
24+
court.effectiveStake = totalStake;
25+
court.save();
26+
27+
if (court.parent && court.parent !== null) {
28+
court = Court.load(court.parent as string);
29+
} else {
30+
break;
31+
}
32+
}
33+
}
34+
635
export function createCourtFromEvent(event: CourtCreated): void {
736
const court = new Court(event.params._courtID.toString());
837
court.hiddenVotes = event.params._hiddenVotes;
@@ -17,8 +46,10 @@ export function createCourtFromEvent(event: CourtCreated): void {
1746
court.numberClosedDisputes = ZERO;
1847
court.numberVotingDisputes = ZERO;
1948
court.numberAppealingDisputes = ZERO;
49+
court.numberVotes = ZERO;
2050
court.numberStakedJurors = ZERO;
2151
court.stake = ZERO;
52+
court.effectiveStake = ZERO;
2253
court.delayedStake = ZERO;
2354
court.paidETH = ZERO;
2455
court.paidPNK = ZERO;

subgraph/core/src/entities/JurorTokensPerCourt.ts

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { updateActiveJurors, getDelta, updateStakedPNK } from "../datapoint";
44
import { ensureUser } from "./User";
55
import { ONE, ZERO } from "../utils";
66
import { SortitionModule } from "../../generated/SortitionModule/SortitionModule";
7+
import { updateEffectiveStake } from "./Court";
78

89
export function ensureJurorTokensPerCourt(jurorAddress: string, courtID: string): JurorTokensPerCourt {
910
const id = `${jurorAddress}-${courtID}`;
@@ -59,6 +60,7 @@ export function updateJurorStake(
5960
updateActiveJurors(activeJurorsDelta, timestamp);
6061
juror.save();
6162
court.save();
63+
updateEffectiveStake(courtID);
6264
}
6365

6466
export function updateJurorDelayedStake(jurorAddress: string, courtID: string, amount: BigInt): void {

subgraph/core/src/entities/TokenAndEthShift.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export function updateTokenAndEthShiftFromEvent(event: TokenAndETHShiftEvent): v
2929
const previousEthAmount = shift.ethAmount;
3030
const newEthAmount = previousEthAmount.plus(ethAmount);
3131
shift.ethAmount = newEthAmount;
32-
resolveUserDispute(jurorAddress.toHexString(), previousEthAmount, newEthAmount, disputeID.toString());
32+
resolveUserDispute(jurorAddress.toHexString(), disputeID.toString());
3333
court.paidETH = court.paidETH.plus(ethAmount);
3434
updatePaidETH(ethAmount, event.block.timestamp);
3535
if (pnkAmount.gt(ZERO)) {

subgraph/core/src/entities/User.ts

+6-20
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ import { BigInt, BigDecimal } from "@graphprotocol/graph-ts";
22
import { User } from "../../generated/schema";
33
import { ONE, ZERO } from "../utils";
44

5-
export function computeCoherenceScore(totalCoherent: BigInt, totalResolvedDisputes: BigInt): BigInt {
5+
export function computeCoherenceScore(totalCoherentVotes: BigInt, totalResolvedVotes: BigInt): BigInt {
66
const smoothingFactor = BigDecimal.fromString("10");
77

8-
let denominator = totalResolvedDisputes.toBigDecimal().plus(smoothingFactor);
9-
let coherencyRatio = totalCoherent.toBigDecimal().div(denominator);
8+
let denominator = totalResolvedVotes.toBigDecimal().plus(smoothingFactor);
9+
let coherencyRatio = totalCoherentVotes.toBigDecimal().div(denominator);
1010

1111
const coherencyScore = coherencyRatio.times(BigDecimal.fromString("100"));
1212

@@ -36,7 +36,8 @@ export function createUserFromAddress(id: string): User {
3636
user.totalResolvedDisputes = ZERO;
3737
user.totalAppealingDisputes = ZERO;
3838
user.totalDisputes = ZERO;
39-
user.totalCoherent = ZERO;
39+
user.totalCoherentVotes = ZERO;
40+
user.totalResolvedVotes = ZERO;
4041
user.coherenceScore = ZERO;
4142
user.save();
4243

@@ -54,28 +55,13 @@ export function addUserActiveDispute(id: string, disputeID: string): void {
5455
user.save();
5556
}
5657

57-
export function resolveUserDispute(id: string, previousFeeAmount: BigInt, feeAmount: BigInt, disputeID: string): void {
58+
export function resolveUserDispute(id: string, disputeID: string): void {
5859
const user = ensureUser(id);
5960
if (user.resolvedDisputes.includes(disputeID)) {
60-
if (previousFeeAmount.gt(ZERO)) {
61-
if (feeAmount.le(ZERO)) {
62-
user.totalCoherent = user.totalCoherent.minus(ONE);
63-
}
64-
} else if (previousFeeAmount.le(ZERO)) {
65-
if (feeAmount.gt(ZERO)) {
66-
user.totalCoherent = user.totalCoherent.plus(ONE);
67-
}
68-
}
69-
user.coherenceScore = computeCoherenceScore(user.totalCoherent, user.totalResolvedDisputes);
70-
user.save();
7161
return;
7262
}
7363
user.resolvedDisputes = user.resolvedDisputes.concat([disputeID]);
7464
user.totalResolvedDisputes = user.totalResolvedDisputes.plus(ONE);
75-
if (feeAmount.gt(ZERO)) {
76-
user.totalCoherent = user.totalCoherent.plus(ONE);
77-
}
7865
user.activeDisputes = user.activeDisputes.minus(ONE);
79-
user.coherenceScore = computeCoherenceScore(user.totalCoherent, user.totalResolvedDisputes);
8066
user.save();
8167
}

subgraph/package.json

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

web/package.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
"eslint-plugin-react-hooks": "^4.6.0",
6969
"lru-cache": "^7.18.3",
7070
"typescript": "^5.3.3",
71+
"vite": "^5.4.2",
7172
"vite-plugin-node-polyfills": "^0.21.0",
7273
"vite-plugin-svgr": "^4.2.0",
7374
"vite-tsconfig-paths": "^4.3.2"
@@ -76,7 +77,7 @@
7677
"@cyntler/react-doc-viewer": "^1.16.3",
7778
"@filebase/client": "^0.0.5",
7879
"@kleros/kleros-sdk": "workspace:^",
79-
"@kleros/ui-components-library": "^2.14.0",
80+
"@kleros/ui-components-library": "^2.15.0",
8081
"@lifi/wallet-management": "^3.0.3",
8182
"@lifi/widget": "^3.2.0",
8283
"@middy/core": "^5.3.2",
@@ -117,6 +118,6 @@
117118
"vanilla-jsoneditor": "^0.21.4",
118119
"viem": "^2.17.3",
119120
"vite": "^5.2.10",
120-
"wagmi": "^2.11.3"
121+
"wagmi": "^2.12.8"
121122
}
122123
}
+44-10
Loading
Loading

web/src/components/DisputeView/DisputeCardView.tsx

+6-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ const CardContainer = styled.div`
2828
flex-direction: column;
2929
justify-content: space-between;
3030
`;
31+
32+
const StyledCaseCardTitleSkeleton = styled(StyledSkeleton)`
33+
margin-bottom: 16px;
34+
`;
35+
3136
const TruncatedTitle = ({ text, maxLength }) => {
3237
const truncatedText = text.length <= maxLength ? text : text.slice(0, maxLength) + "…";
3338
return <h3>{truncatedText}</h3>;
@@ -54,7 +59,7 @@ const DisputeCardView: React.FC<IDisputeCardView> = ({ isLoading, ...props }) =>
5459
<StyledCard hover onClick={() => navigate(`/cases/${props?.disputeID?.toString()}`)}>
5560
<PeriodBanner id={parseInt(props?.disputeID)} period={props?.period} />
5661
<CardContainer>
57-
{isLoading ? <StyledSkeleton /> : <TruncatedTitle text={props?.title} maxLength={100} />}
62+
{isLoading ? <StyledCaseCardTitleSkeleton /> : <TruncatedTitle text={props?.title} maxLength={100} />}
5863
<DisputeInfo {...props} />
5964
</CardContainer>
6065
</StyledCard>

0 commit comments

Comments
 (0)