From 8613090783743eeef9bce3a5f749ee61882d48eb Mon Sep 17 00:00:00 2001 From: kemuru <102478601+kemuru@users.noreply.github.com> Date: Fri, 4 Oct 2024 14:56:16 +0200 Subject: [PATCH 1/8] feat(subgraph,web): add totalcoherentvotes, totalresolvedvotes, modify frontend --- subgraph/core/schema.graphql | 5 ++- subgraph/core/src/KlerosCore.ts | 39 ++++++++++++++++++- .../core/src/entities/TokenAndEthShift.ts | 2 +- subgraph/core/src/entities/User.ts | 20 ++-------- web/.env.devnet.public | 2 +- .../Popup/MiniGuides/JurorLevels.tsx | 24 ++++++------ .../queries/useTopUsersByCoherenceScore.ts | 3 +- web/src/hooks/queries/useUser.ts | 3 +- .../pages/Dashboard/JurorInfo/Coherency.tsx | 10 ++--- web/src/pages/Dashboard/JurorInfo/Header.tsx | 12 +++--- web/src/pages/Dashboard/JurorInfo/index.tsx | 14 ++----- .../Home/TopJurors/JurorCard/Coherency.tsx | 8 ++-- .../Home/TopJurors/JurorCard/DesktopCard.tsx | 10 ++--- .../Home/TopJurors/JurorCard/MobileCard.tsx | 14 +++++-- .../pages/Home/TopJurors/JurorCard/index.tsx | 8 ++-- 15 files changed, 100 insertions(+), 74 deletions(-) diff --git a/subgraph/core/schema.graphql b/subgraph/core/schema.graphql index 36192bc77..112ca7756 100644 --- a/subgraph/core/schema.graphql +++ b/subgraph/core/schema.graphql @@ -79,13 +79,14 @@ type User @entity { resolvedDisputes: [Dispute!]! totalResolvedDisputes: BigInt! totalDisputes: BigInt! - totalCoherent: BigInt! - coherenceScore: BigInt! totalAppealingDisputes: BigInt! votes: [Vote!]! @derivedFrom(field: "juror") contributions: [Contribution!]! @derivedFrom(field: "contributor") evidences: [Evidence!]! @derivedFrom(field: "sender") penalties: [Penalty!]! @derivedFrom(field: "juror") + totalCoherentVotes: BigInt! + totalResolvedVotes: BigInt! + coherenceScore: BigInt! } type Penalty @entity { diff --git a/subgraph/core/src/KlerosCore.ts b/subgraph/core/src/KlerosCore.ts index 650d5a2ff..f237ca6f2 100644 --- a/subgraph/core/src/KlerosCore.ts +++ b/subgraph/core/src/KlerosCore.ts @@ -24,7 +24,7 @@ import { updateJurorStake } from "./entities/JurorTokensPerCourt"; import { createDrawFromEvent } from "./entities/Draw"; import { updateTokenAndEthShiftFromEvent } from "./entities/TokenAndEthShift"; import { updateArbitrableCases } from "./entities/Arbitrable"; -import { Court, Dispute, Round, User } from "../generated/schema"; +import { ClassicVote, Court, Dispute, Draw, Round, User } from "../generated/schema"; import { BigInt } from "@graphprotocol/graph-ts"; import { updatePenalty } from "./entities/Penalty"; import { ensureFeeToken } from "./entities/FeeToken"; @@ -124,6 +124,43 @@ export function handleNewPeriod(event: NewPeriod): void { dispute.currentRuling = currentRulingInfo.getRuling(); dispute.overridden = currentRulingInfo.getOverridden(); dispute.tied = currentRulingInfo.getTied(); + dispute.save(); + + const rounds = dispute.rounds.load(); + for (let i = 0; i < rounds.length; i++) { + const round = Round.load(rounds[i].id); + if (!round) continue; + + const draws = round.drawnJurors.load(); + // Iterate over all draws in the round + for (let j = 0; j < draws.length; j++) { + const draw = Draw.load(draws[j].id); + if (!draw) continue; + + // This will only work for Classic DisputeKit ("1-"). + const vote = ClassicVote.load(`1-${draw.id}`); + + if (!vote) continue; + + const juror = ensureUser(draw.juror); + juror.totalResolvedVotes = juror.totalResolvedVotes.plus(ONE); + + if (vote.choice === null) continue; + + // Check if the vote choice matches the final ruling + if (vote.choice!.equals(dispute.currentRuling)) { + juror.totalCoherentVotes = juror.totalCoherentVotes.plus(ONE); + } + + // Recalculate coherenceScore + if (juror.totalResolvedVotes.gt(ZERO)) { + const coherenceScore = juror.totalCoherentVotes.times(BigInt.fromI32(100)).div(juror.totalResolvedVotes); + juror.coherenceScore = coherenceScore; + } + + juror.save(); + } + } } dispute.period = newPeriod; diff --git a/subgraph/core/src/entities/TokenAndEthShift.ts b/subgraph/core/src/entities/TokenAndEthShift.ts index 5fca5dec4..6225c3d17 100644 --- a/subgraph/core/src/entities/TokenAndEthShift.ts +++ b/subgraph/core/src/entities/TokenAndEthShift.ts @@ -29,7 +29,7 @@ export function updateTokenAndEthShiftFromEvent(event: TokenAndETHShiftEvent): v const previousEthAmount = shift.ethAmount; const newEthAmount = previousEthAmount.plus(ethAmount); shift.ethAmount = newEthAmount; - resolveUserDispute(jurorAddress.toHexString(), previousEthAmount, newEthAmount, disputeID.toString()); + resolveUserDispute(jurorAddress.toHexString(), disputeID.toString()); court.paidETH = court.paidETH.plus(ethAmount); updatePaidETH(ethAmount, event.block.timestamp); if (pnkAmount.gt(ZERO)) { diff --git a/subgraph/core/src/entities/User.ts b/subgraph/core/src/entities/User.ts index 85a9da833..3cfe44a12 100644 --- a/subgraph/core/src/entities/User.ts +++ b/subgraph/core/src/entities/User.ts @@ -36,7 +36,8 @@ export function createUserFromAddress(id: string): User { user.totalResolvedDisputes = ZERO; user.totalAppealingDisputes = ZERO; user.totalDisputes = ZERO; - user.totalCoherent = ZERO; + user.totalCoherentVotes = ZERO; + user.totalResolvedVotes = ZERO; user.coherenceScore = ZERO; user.save(); @@ -54,28 +55,13 @@ export function addUserActiveDispute(id: string, disputeID: string): void { user.save(); } -export function resolveUserDispute(id: string, previousFeeAmount: BigInt, feeAmount: BigInt, disputeID: string): void { +export function resolveUserDispute(id: string, disputeID: string): void { const user = ensureUser(id); if (user.resolvedDisputes.includes(disputeID)) { - if (previousFeeAmount.gt(ZERO)) { - if (feeAmount.le(ZERO)) { - user.totalCoherent = user.totalCoherent.minus(ONE); - } - } else if (previousFeeAmount.le(ZERO)) { - if (feeAmount.gt(ZERO)) { - user.totalCoherent = user.totalCoherent.plus(ONE); - } - } - user.coherenceScore = computeCoherenceScore(user.totalCoherent, user.totalResolvedDisputes); - user.save(); return; } user.resolvedDisputes = user.resolvedDisputes.concat([disputeID]); user.totalResolvedDisputes = user.totalResolvedDisputes.plus(ONE); - if (feeAmount.gt(ZERO)) { - user.totalCoherent = user.totalCoherent.plus(ONE); - } user.activeDisputes = user.activeDisputes.minus(ONE); - user.coherenceScore = computeCoherenceScore(user.totalCoherent, user.totalResolvedDisputes); user.save(); } diff --git a/web/.env.devnet.public b/web/.env.devnet.public index 0fca24c7b..652aa9225 100644 --- a/web/.env.devnet.public +++ b/web/.env.devnet.public @@ -1,6 +1,6 @@ # Do not enter sensitive information here. export REACT_APP_DEPLOYMENT=devnet -export REACT_APP_CORE_SUBGRAPH=https://api.studio.thegraph.com/query/61738/kleros-v2-core-devnet/version/latest +export REACT_APP_CORE_SUBGRAPH=https://api.studio.thegraph.com/query/44313/kleros-v2-test/version/latest export REACT_APP_DRT_ARBSEPOLIA_SUBGRAPH=https://api.studio.thegraph.com/query/61738/kleros-v2-drt-arbisep-devnet/version/latest export REACT_APP_STATUS_URL=https://kleros-v2-devnet.betteruptime.com/badge export REACT_APP_GENESIS_BLOCK_ARBSEPOLIA=3084598 diff --git a/web/src/components/Popup/MiniGuides/JurorLevels.tsx b/web/src/components/Popup/MiniGuides/JurorLevels.tsx index 43bd79a54..6d1083211 100644 --- a/web/src/components/Popup/MiniGuides/JurorLevels.tsx +++ b/web/src/components/Popup/MiniGuides/JurorLevels.tsx @@ -63,32 +63,32 @@ const userLevelData = [ { level: 1, title: "Phytagoras", - totalCoherent: 6, - totalResolvedDisputes: 10, + totalCoherentVotes: 6, + totalResolvedVotes: 10, }, { level: 2, title: "Socrates", - totalCoherent: 7, - totalResolvedDisputes: 10, + totalCoherentVotes: 7, + totalResolvedVotes: 10, }, { level: 3, title: "Plato", - totalCoherent: 8, - totalResolvedDisputes: 10, + totalCoherentVotes: 8, + totalResolvedVotes: 10, }, { level: 4, title: "Aristotle", - totalCoherent: 9, - totalResolvedDisputes: 10, + totalCoherentVotes: 9, + totalResolvedVotes: 10, }, { level: 0, title: "Diogenes", - totalCoherent: 3, - totalResolvedDisputes: 10, + totalCoherentVotes: 3, + totalResolvedVotes: 10, }, ]; @@ -114,8 +114,8 @@ const RightContent: React.FC<{ currentPage: number }> = ({ currentPage }) => { diff --git a/web/src/hooks/queries/useTopUsersByCoherenceScore.ts b/web/src/hooks/queries/useTopUsersByCoherenceScore.ts index f45ad08d5..add534914 100644 --- a/web/src/hooks/queries/useTopUsersByCoherenceScore.ts +++ b/web/src/hooks/queries/useTopUsersByCoherenceScore.ts @@ -12,7 +12,8 @@ const topUsersByCoherenceScoreQuery = graphql(` users(first: $first, orderBy: $orderBy, orderDirection: $orderDirection) { id coherenceScore - totalCoherent + totalCoherentVotes + totalResolvedVotes totalResolvedDisputes } } diff --git a/web/src/hooks/queries/useUser.ts b/web/src/hooks/queries/useUser.ts index 0fe7216c0..d453035c9 100644 --- a/web/src/hooks/queries/useUser.ts +++ b/web/src/hooks/queries/useUser.ts @@ -12,7 +12,8 @@ export const userFragment = graphql(` totalDisputes totalResolvedDisputes totalAppealingDisputes - totalCoherent + totalCoherentVotes + totalResolvedVotes coherenceScore tokens { court { diff --git a/web/src/pages/Dashboard/JurorInfo/Coherency.tsx b/web/src/pages/Dashboard/JurorInfo/Coherency.tsx index bef8db218..ae164a75d 100644 --- a/web/src/pages/Dashboard/JurorInfo/Coherency.tsx +++ b/web/src/pages/Dashboard/JurorInfo/Coherency.tsx @@ -30,18 +30,18 @@ interface ICoherency { level: number; title: string; }; - totalCoherent: number; - totalResolvedDisputes: number; + totalCoherentVotes: number; + totalResolvedVotes: number; isMiniGuide: boolean; } -const Coherency: React.FC = ({ userLevelData, totalCoherent, totalResolvedDisputes, isMiniGuide }) => { +const Coherency: React.FC = ({ userLevelData, totalCoherentVotes, totalResolvedVotes, isMiniGuide }) => { const votesContent = ( ); @@ -51,7 +51,7 @@ const Coherency: React.FC = ({ userLevelData, totalCoherent, totalRe {userLevelData.title} {!isMiniGuide ? ( diff --git a/web/src/pages/Dashboard/JurorInfo/Header.tsx b/web/src/pages/Dashboard/JurorInfo/Header.tsx index 8db90b3c8..459e6c143 100644 --- a/web/src/pages/Dashboard/JurorInfo/Header.tsx +++ b/web/src/pages/Dashboard/JurorInfo/Header.tsx @@ -65,16 +65,16 @@ const StyledLink = styled.a` interface IHeader { levelTitle: string; levelNumber: number; - totalCoherent: number; - totalResolvedDisputes: number; + totalCoherentVotes: number; + totalResolvedVotes: number; } -const Header: React.FC = ({ levelTitle, levelNumber, totalCoherent, totalResolvedDisputes }) => { +const Header: React.FC = ({ levelTitle, levelNumber, totalCoherentVotes, totalResolvedVotes }) => { const [isJurorLevelsMiniGuideOpen, toggleJurorLevelsMiniGuide] = useToggle(false); - const coherencePercentage = parseFloat(((totalCoherent / Math.max(totalResolvedDisputes, 1)) * 100).toFixed(2)); + const coherencePercentage = parseFloat(((totalCoherentVotes / Math.max(totalResolvedVotes, 1)) * 100).toFixed(2)); const courtUrl = window.location.origin; - const xPostText = `Hey I've been busy as a Juror on the Kleros court, check out my score: \n\nLevel: ${levelNumber} (${levelTitle})\nCoherence Percentage: ${coherencePercentage}%\nCoherent Votes: ${totalCoherent}/${totalResolvedDisputes}\n\nBe a juror with me! ➡️ ${courtUrl}`; + const xPostText = `Hey I've been busy as a Juror on the Kleros court, check out my score: \n\nLevel: ${levelNumber} (${levelTitle})\nCoherence Percentage: ${coherencePercentage}%\nCoherent Votes: ${totalCoherentVotes}/${totalResolvedVotes}\n\nBe a juror with me! ➡️ ${courtUrl}`; const xShareUrl = `https://twitter.com/intent/tweet?text=${encodeURIComponent(xPostText)}`; return ( @@ -86,7 +86,7 @@ const Header: React.FC = ({ levelTitle, levelNumber, totalCoherent, tot toggleMiniGuide={toggleJurorLevelsMiniGuide} MiniGuideComponent={JurorLevels} /> - {totalResolvedDisputes > 0 ? ( + {totalResolvedVotes > 0 ? ( Share your juror score diff --git a/web/src/pages/Dashboard/JurorInfo/index.tsx b/web/src/pages/Dashboard/JurorInfo/index.tsx index dc0609ed9..a944f74c5 100644 --- a/web/src/pages/Dashboard/JurorInfo/index.tsx +++ b/web/src/pages/Dashboard/JurorInfo/index.tsx @@ -44,8 +44,8 @@ const JurorInfo: React.FC = () => { const { data } = useUserQuery(address?.toLowerCase() as `0x${string}`); // TODO check graph schema const coherenceScore = data?.user ? parseInt(data?.user?.coherenceScore) : 0; - const totalCoherent = data?.user ? parseInt(data?.user?.totalCoherent) : 0; - const totalResolvedDisputes = data?.user ? parseInt(data?.user?.totalResolvedDisputes) : 0; + const totalCoherentVotes = data?.user ? parseInt(data?.user?.totalCoherentVotes) : 0; + const totalResolvedVotes = data?.user ? parseInt(data?.user?.totalResolvedVotes) : 0; const userLevelData = getUserLevelData(coherenceScore); @@ -54,17 +54,11 @@ const JurorInfo: React.FC = () => {
- + diff --git a/web/src/pages/Home/TopJurors/JurorCard/Coherency.tsx b/web/src/pages/Home/TopJurors/JurorCard/Coherency.tsx index 7b3b19448..3a57c46a8 100644 --- a/web/src/pages/Home/TopJurors/JurorCard/Coherency.tsx +++ b/web/src/pages/Home/TopJurors/JurorCard/Coherency.tsx @@ -11,12 +11,12 @@ const Container = styled.div` `; interface ICoherency { - totalCoherent: number; - totalResolvedDisputes: number; + totalCoherentVotes: number; + totalResolvedVotes: number; } -const Coherency: React.FC = ({ totalCoherent, totalResolvedDisputes }) => { - const coherenceRatio = `${totalCoherent}/${totalResolvedDisputes}`; +const Coherency: React.FC = ({ totalCoherentVotes, totalResolvedVotes }) => { + const coherenceRatio = `${totalCoherentVotes}/${totalResolvedVotes}`; return {coherenceRatio}; }; diff --git a/web/src/pages/Home/TopJurors/JurorCard/DesktopCard.tsx b/web/src/pages/Home/TopJurors/JurorCard/DesktopCard.tsx index 12b39f4c2..8b50eb877 100644 --- a/web/src/pages/Home/TopJurors/JurorCard/DesktopCard.tsx +++ b/web/src/pages/Home/TopJurors/JurorCard/DesktopCard.tsx @@ -33,16 +33,16 @@ const Container = styled.div` interface IDesktopCard { rank: number; address: string; - totalCoherent: number; - totalResolvedDisputes: number; + totalCoherentVotes: number; + totalResolvedVotes: number; coherenceScore: number; } const DesktopCard: React.FC = ({ rank, address, - totalCoherent, - totalResolvedDisputes, + totalCoherentVotes, + totalResolvedVotes, coherenceScore, }) => { return ( @@ -50,7 +50,7 @@ const DesktopCard: React.FC = ({ - + ); diff --git a/web/src/pages/Home/TopJurors/JurorCard/MobileCard.tsx b/web/src/pages/Home/TopJurors/JurorCard/MobileCard.tsx index 54f0be3e1..295bd978f 100644 --- a/web/src/pages/Home/TopJurors/JurorCard/MobileCard.tsx +++ b/web/src/pages/Home/TopJurors/JurorCard/MobileCard.tsx @@ -75,11 +75,17 @@ interface IMobileCard { rank: number; address: string; coherenceScore: number; - totalCoherent: number; - totalResolvedDisputes: number; + totalCoherentVotes: number; + totalResolvedVotes: number; } -const MobileCard: React.FC = ({ rank, address, coherenceScore, totalCoherent, totalResolvedDisputes }) => { +const MobileCard: React.FC = ({ + rank, + address, + coherenceScore, + totalCoherentVotes, + totalResolvedVotes, +}) => { return ( @@ -96,7 +102,7 @@ const MobileCard: React.FC = ({ rank, address, coherenceScore, tota - + diff --git a/web/src/pages/Home/TopJurors/JurorCard/index.tsx b/web/src/pages/Home/TopJurors/JurorCard/index.tsx index 9ae084dbf..4d8732e6c 100644 --- a/web/src/pages/Home/TopJurors/JurorCard/index.tsx +++ b/web/src/pages/Home/TopJurors/JurorCard/index.tsx @@ -7,12 +7,12 @@ interface IJurorCard { rank: number; address: `0x${string}`; coherenceScore: number; - totalCoherent: number; - totalResolvedDisputes: number; + totalCoherentVotes: number; + totalResolvedVotes: number; } -const JurorCard: React.FC = ({ rank, address, coherenceScore, totalCoherent, totalResolvedDisputes }) => { - const allProps = { rank, address, coherenceScore, totalCoherent, totalResolvedDisputes }; +const JurorCard: React.FC = ({ rank, address, coherenceScore, totalCoherentVotes, totalResolvedVotes }) => { + const allProps = { rank, address, coherenceScore, totalCoherentVotes, totalResolvedVotes }; return ( <> From 61bffc7457f8c5fae691683410ece0b8a979b775 Mon Sep 17 00:00:00 2001 From: kemuru <102478601+kemuru@users.noreply.github.com> Date: Fri, 4 Oct 2024 16:30:35 +0200 Subject: [PATCH 2/8] fix: juror levels calculations according to the figma --- web/src/pages/Dashboard/JurorInfo/index.tsx | 3 +- .../Home/TopJurors/JurorCard/DesktopCard.tsx | 4 +- .../Home/TopJurors/JurorCard/JurorLevel.tsx | 5 ++- .../Home/TopJurors/JurorCard/MobileCard.tsx | 4 +- .../pages/Home/TopJurors/JurorCard/index.tsx | 12 +++++- web/src/utils/userLevelCalculation.ts | 38 +++++++++++++------ 6 files changed, 48 insertions(+), 18 deletions(-) diff --git a/web/src/pages/Dashboard/JurorInfo/index.tsx b/web/src/pages/Dashboard/JurorInfo/index.tsx index a944f74c5..db9f3ba43 100644 --- a/web/src/pages/Dashboard/JurorInfo/index.tsx +++ b/web/src/pages/Dashboard/JurorInfo/index.tsx @@ -46,8 +46,9 @@ const JurorInfo: React.FC = () => { const coherenceScore = data?.user ? parseInt(data?.user?.coherenceScore) : 0; const totalCoherentVotes = data?.user ? parseInt(data?.user?.totalCoherentVotes) : 0; const totalResolvedVotes = data?.user ? parseInt(data?.user?.totalResolvedVotes) : 0; + const totalResolvedDisputes = data?.user ? parseInt(data?.user?.totalResolvedDisputes) : 0; - const userLevelData = getUserLevelData(coherenceScore); + const userLevelData = getUserLevelData(coherenceScore, totalResolvedDisputes); return ( diff --git a/web/src/pages/Home/TopJurors/JurorCard/DesktopCard.tsx b/web/src/pages/Home/TopJurors/JurorCard/DesktopCard.tsx index 8b50eb877..dddc5112b 100644 --- a/web/src/pages/Home/TopJurors/JurorCard/DesktopCard.tsx +++ b/web/src/pages/Home/TopJurors/JurorCard/DesktopCard.tsx @@ -35,6 +35,7 @@ interface IDesktopCard { address: string; totalCoherentVotes: number; totalResolvedVotes: number; + totalResolvedDisputes: number; coherenceScore: number; } @@ -43,6 +44,7 @@ const DesktopCard: React.FC = ({ address, totalCoherentVotes, totalResolvedVotes, + totalResolvedDisputes, coherenceScore, }) => { return ( @@ -51,7 +53,7 @@ const DesktopCard: React.FC = ({ - + ); }; diff --git a/web/src/pages/Home/TopJurors/JurorCard/JurorLevel.tsx b/web/src/pages/Home/TopJurors/JurorCard/JurorLevel.tsx index 3becac4c0..cdfce9ed2 100644 --- a/web/src/pages/Home/TopJurors/JurorCard/JurorLevel.tsx +++ b/web/src/pages/Home/TopJurors/JurorCard/JurorLevel.tsx @@ -40,10 +40,11 @@ const StyledLabel = styled.label` interface IJurorLevel { coherenceScore: number; + totalResolvedDisputes: number; } -const JurorLevel: React.FC = ({ coherenceScore }) => { - const userLevelData = getUserLevelData(coherenceScore); +const JurorLevel: React.FC = ({ coherenceScore, totalResolvedDisputes }) => { + const userLevelData = getUserLevelData(coherenceScore, totalResolvedDisputes); const level = userLevelData.level; return ( diff --git a/web/src/pages/Home/TopJurors/JurorCard/MobileCard.tsx b/web/src/pages/Home/TopJurors/JurorCard/MobileCard.tsx index 295bd978f..dd34de339 100644 --- a/web/src/pages/Home/TopJurors/JurorCard/MobileCard.tsx +++ b/web/src/pages/Home/TopJurors/JurorCard/MobileCard.tsx @@ -77,6 +77,7 @@ interface IMobileCard { coherenceScore: number; totalCoherentVotes: number; totalResolvedVotes: number; + totalResolvedDisputes: number; } const MobileCard: React.FC = ({ @@ -85,6 +86,7 @@ const MobileCard: React.FC = ({ coherenceScore, totalCoherentVotes, totalResolvedVotes, + totalResolvedDisputes, }) => { return ( @@ -93,7 +95,7 @@ const MobileCard: React.FC = ({ - + diff --git a/web/src/pages/Home/TopJurors/JurorCard/index.tsx b/web/src/pages/Home/TopJurors/JurorCard/index.tsx index 4d8732e6c..6b6a5c973 100644 --- a/web/src/pages/Home/TopJurors/JurorCard/index.tsx +++ b/web/src/pages/Home/TopJurors/JurorCard/index.tsx @@ -9,10 +9,18 @@ interface IJurorCard { coherenceScore: number; totalCoherentVotes: number; totalResolvedVotes: number; + totalResolvedDisputes: number; } -const JurorCard: React.FC = ({ rank, address, coherenceScore, totalCoherentVotes, totalResolvedVotes }) => { - const allProps = { rank, address, coherenceScore, totalCoherentVotes, totalResolvedVotes }; +const JurorCard: React.FC = ({ + rank, + address, + coherenceScore, + totalCoherentVotes, + totalResolvedVotes, + totalResolvedDisputes, +}) => { + const allProps = { rank, address, coherenceScore, totalCoherentVotes, totalResolvedVotes, totalResolvedDisputes }; return ( <> diff --git a/web/src/utils/userLevelCalculation.ts b/web/src/utils/userLevelCalculation.ts index 69344098e..18ace2976 100644 --- a/web/src/utils/userLevelCalculation.ts +++ b/web/src/utils/userLevelCalculation.ts @@ -1,15 +1,31 @@ export const levelTitles = [ - { scoreRange: [0, 20], level: 0, title: "Diogenes" }, - { scoreRange: [20, 40], level: 1, title: "Pythagoras" }, - { scoreRange: [40, 60], level: 2, title: "Socrates" }, - { scoreRange: [60, 80], level: 3, title: "Plato" }, - { scoreRange: [80, 100], level: 4, title: "Aristotle" }, + { level: 0, title: "Diogenes" }, + { level: 1, title: "Pythagoras" }, + { level: 2, title: "Socrates" }, + { level: 3, title: "Plato" }, + { level: 4, title: "Aristotle" }, ]; -export const getUserLevelData = (coherencyScore: number) => { - return ( - levelTitles.find(({ scoreRange }) => { - return coherencyScore >= scoreRange[0] && coherencyScore < scoreRange[1]; - }) ?? levelTitles[0] - ); +export const getUserLevelData = (coherencyScore: number, totalResolvedDisputes: number) => { + if (totalResolvedDisputes >= 3 && coherencyScore < 50) { + return levelTitles.find(({ level }) => level === 0); + } + + if (totalResolvedDisputes === 0 || (totalResolvedDisputes >= 1 && coherencyScore >= 0 && coherencyScore <= 70)) { + return levelTitles.find(({ level }) => level === 1); + } + + if (totalResolvedDisputes >= 3 && coherencyScore > 70 && coherencyScore <= 80) { + return levelTitles.find(({ level }) => level === 2); + } + + if (totalResolvedDisputes >= 7 && coherencyScore > 80 && coherencyScore <= 90) { + return levelTitles.find(({ level }) => level === 3); + } + + if (totalResolvedDisputes >= 10 && coherencyScore > 90) { + return levelTitles.find(({ level }) => level === 4); + } + + return levelTitles.find(({ level }) => level === 1); }; From 061b22a5cc31215cc9c50eeecc7ea8cf2a7af9d1 Mon Sep 17 00:00:00 2001 From: kemuru <102478601+kemuru@users.noreply.github.com> Date: Mon, 7 Oct 2024 09:08:11 +0200 Subject: [PATCH 3/8] chore: delete totalcoherent references, delete computecoherence test, improve level calculation --- subgraph/core/src/entities/User.ts | 14 -------- subgraph/core/tests/user.test.ts | 9 ----- web/src/utils/userLevelCalculation.ts | 48 +++++++++++++-------------- 3 files changed, 23 insertions(+), 48 deletions(-) delete mode 100644 subgraph/core/tests/user.test.ts diff --git a/subgraph/core/src/entities/User.ts b/subgraph/core/src/entities/User.ts index 3cfe44a12..dc5932277 100644 --- a/subgraph/core/src/entities/User.ts +++ b/subgraph/core/src/entities/User.ts @@ -1,20 +1,6 @@ -import { BigInt, BigDecimal } from "@graphprotocol/graph-ts"; import { User } from "../../generated/schema"; import { ONE, ZERO } from "../utils"; -export function computeCoherenceScore(totalCoherent: BigInt, totalResolvedDisputes: BigInt): BigInt { - const smoothingFactor = BigDecimal.fromString("10"); - - let denominator = totalResolvedDisputes.toBigDecimal().plus(smoothingFactor); - let coherencyRatio = totalCoherent.toBigDecimal().div(denominator); - - const coherencyScore = coherencyRatio.times(BigDecimal.fromString("100")); - - const roundedScore = coherencyScore.plus(BigDecimal.fromString("0.5")); - - return BigInt.fromString(roundedScore.toString().split(".")[0]); -} - export function ensureUser(id: string): User { const user = User.load(id); diff --git a/subgraph/core/tests/user.test.ts b/subgraph/core/tests/user.test.ts deleted file mode 100644 index c69548b48..000000000 --- a/subgraph/core/tests/user.test.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { assert, test, describe } from "matchstick-as/assembly/index"; -import { BigInt } from "@graphprotocol/graph-ts"; -import { computeCoherenceScore } from "../src/entities/User"; - -describe("Compute coherence score", () => { - test("Slam BigInts together", () => { - assert.bigIntEquals(BigInt.fromI32(8), computeCoherenceScore(BigInt.fromI32(1), BigInt.fromI32(2))); - }); -}); diff --git a/web/src/utils/userLevelCalculation.ts b/web/src/utils/userLevelCalculation.ts index 18ace2976..e77071786 100644 --- a/web/src/utils/userLevelCalculation.ts +++ b/web/src/utils/userLevelCalculation.ts @@ -1,31 +1,29 @@ -export const levelTitles = [ - { level: 0, title: "Diogenes" }, - { level: 1, title: "Pythagoras" }, - { level: 2, title: "Socrates" }, - { level: 3, title: "Plato" }, - { level: 4, title: "Aristotle" }, +interface ILevelCriteria { + level: number; + title: string; + minDisputes: number; + minScore: number; + maxScore: number; +} + +const levelCriteria: ILevelCriteria[] = [ + { level: 0, title: "Diogenes", minDisputes: 3, minScore: 0, maxScore: 49 }, + { level: 1, title: "Pythagoras", minDisputes: 0, minScore: 0, maxScore: 70 }, + { level: 2, title: "Socrates", minDisputes: 3, minScore: 71, maxScore: 80 }, + { level: 3, title: "Plato", minDisputes: 7, minScore: 81, maxScore: 90 }, + { level: 4, title: "Aristotle", minDisputes: 10, minScore: 91, maxScore: 100 }, ]; export const getUserLevelData = (coherencyScore: number, totalResolvedDisputes: number) => { - if (totalResolvedDisputes >= 3 && coherencyScore < 50) { - return levelTitles.find(({ level }) => level === 0); - } - - if (totalResolvedDisputes === 0 || (totalResolvedDisputes >= 1 && coherencyScore >= 0 && coherencyScore <= 70)) { - return levelTitles.find(({ level }) => level === 1); - } - - if (totalResolvedDisputes >= 3 && coherencyScore > 70 && coherencyScore <= 80) { - return levelTitles.find(({ level }) => level === 2); - } - - if (totalResolvedDisputes >= 7 && coherencyScore > 80 && coherencyScore <= 90) { - return levelTitles.find(({ level }) => level === 3); - } - - if (totalResolvedDisputes >= 10 && coherencyScore > 90) { - return levelTitles.find(({ level }) => level === 4); + for (const criteria of levelCriteria) { + if ( + totalResolvedDisputes >= criteria.minDisputes && + coherencyScore >= criteria.minScore && + coherencyScore <= criteria.maxScore + ) { + return levelCriteria.find(({ level }) => level === criteria.level); + } } - return levelTitles.find(({ level }) => level === 1); + return levelCriteria.find(({ level }) => level === 1); }; From 8c2903e38ad2c71dd65b84bd9ed6d326b8314f7b Mon Sep 17 00:00:00 2001 From: kemuru <102478601+kemuru@users.noreply.github.com> Date: Mon, 7 Oct 2024 10:31:28 +0200 Subject: [PATCH 4/8] fix(subgraph): get the disputekit id from the round instead of hardcoding it to 1 --- subgraph/core/schema.graphql | 6 +++--- subgraph/core/src/KlerosCore.ts | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/subgraph/core/schema.graphql b/subgraph/core/schema.graphql index 112ca7756..c42f1d939 100644 --- a/subgraph/core/schema.graphql +++ b/subgraph/core/schema.graphql @@ -80,13 +80,13 @@ type User @entity { totalResolvedDisputes: BigInt! totalDisputes: BigInt! totalAppealingDisputes: BigInt! + totalCoherentVotes: BigInt! + totalResolvedVotes: BigInt! + coherenceScore: BigInt! votes: [Vote!]! @derivedFrom(field: "juror") contributions: [Contribution!]! @derivedFrom(field: "contributor") evidences: [Evidence!]! @derivedFrom(field: "sender") penalties: [Penalty!]! @derivedFrom(field: "juror") - totalCoherentVotes: BigInt! - totalResolvedVotes: BigInt! - coherenceScore: BigInt! } type Penalty @entity { diff --git a/subgraph/core/src/KlerosCore.ts b/subgraph/core/src/KlerosCore.ts index f237ca6f2..cee17af9e 100644 --- a/subgraph/core/src/KlerosCore.ts +++ b/subgraph/core/src/KlerosCore.ts @@ -137,8 +137,8 @@ export function handleNewPeriod(event: NewPeriod): void { const draw = Draw.load(draws[j].id); if (!draw) continue; - // This will only work for Classic DisputeKit ("1-"). - const vote = ClassicVote.load(`1-${draw.id}`); + // Since this is a ClassicVote entity, this will only work for the Classic DisputeKit (which has ID "1"). + const vote = ClassicVote.load(`${round.disputeKit}-${draw.id}`); if (!vote) continue; From 9ada4341f71c75f525629d4bee884b77bb740c3c Mon Sep 17 00:00:00 2001 From: kemuru <102478601+kemuru@users.noreply.github.com> Date: Mon, 7 Oct 2024 10:38:25 +0200 Subject: [PATCH 5/8] chore(subgraph): remove unnecessary dispute save --- subgraph/core/src/KlerosCore.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/subgraph/core/src/KlerosCore.ts b/subgraph/core/src/KlerosCore.ts index cee17af9e..034b9dfa3 100644 --- a/subgraph/core/src/KlerosCore.ts +++ b/subgraph/core/src/KlerosCore.ts @@ -124,7 +124,6 @@ export function handleNewPeriod(event: NewPeriod): void { dispute.currentRuling = currentRulingInfo.getRuling(); dispute.overridden = currentRulingInfo.getOverridden(); dispute.tied = currentRulingInfo.getTied(); - dispute.save(); const rounds = dispute.rounds.load(); for (let i = 0; i < rounds.length; i++) { From 952ccf05b9f04257f38ba0b756297b9a5b6832c2 Mon Sep 17 00:00:00 2001 From: kemuru <102478601+kemuru@users.noreply.github.com> Date: Mon, 7 Oct 2024 12:45:32 +0200 Subject: [PATCH 6/8] feat: deploy core subgraphs, update packagejson version and env variable --- subgraph/package.json | 2 +- web/.env.devnet.public | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/subgraph/package.json b/subgraph/package.json index 9448c3b0b..5beaa8af6 100644 --- a/subgraph/package.json +++ b/subgraph/package.json @@ -1,6 +1,6 @@ { "name": "@kleros/kleros-v2-subgraph", - "version": "0.7.4", + "version": "0.7.5", "license": "MIT", "scripts": { "update:core:arbitrum-sepolia-devnet": "./scripts/update.sh arbitrumSepoliaDevnet arbitrum-sepolia core/subgraph.yaml", diff --git a/web/.env.devnet.public b/web/.env.devnet.public index 652aa9225..0fca24c7b 100644 --- a/web/.env.devnet.public +++ b/web/.env.devnet.public @@ -1,6 +1,6 @@ # Do not enter sensitive information here. export REACT_APP_DEPLOYMENT=devnet -export REACT_APP_CORE_SUBGRAPH=https://api.studio.thegraph.com/query/44313/kleros-v2-test/version/latest +export REACT_APP_CORE_SUBGRAPH=https://api.studio.thegraph.com/query/61738/kleros-v2-core-devnet/version/latest export REACT_APP_DRT_ARBSEPOLIA_SUBGRAPH=https://api.studio.thegraph.com/query/61738/kleros-v2-drt-arbisep-devnet/version/latest export REACT_APP_STATUS_URL=https://kleros-v2-devnet.betteruptime.com/badge export REACT_APP_GENESIS_BLOCK_ARBSEPOLIA=3084598 From 3a61b38f148760a067945794c480aa44487db569 Mon Sep 17 00:00:00 2001 From: kemuru <102478601+kemuru@users.noreply.github.com> Date: Mon, 7 Oct 2024 13:32:36 +0200 Subject: [PATCH 7/8] fix: smoothing factor into the coherence score --- subgraph/core/src/KlerosCore.ts | 5 ++--- subgraph/core/src/entities/User.ts | 14 ++++++++++++++ subgraph/package.json | 2 +- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/subgraph/core/src/KlerosCore.ts b/subgraph/core/src/KlerosCore.ts index 7af136375..8f968f83d 100644 --- a/subgraph/core/src/KlerosCore.ts +++ b/subgraph/core/src/KlerosCore.ts @@ -19,7 +19,7 @@ import { createDisputeKitFromEvent, filterSupportedDisputeKits } from "./entitie import { createDisputeFromEvent } from "./entities/Dispute"; import { createRoundFromRoundInfo, updateRoundTimeline } from "./entities/Round"; import { updateCases, updateCasesAppealing, updateCasesRuled, updateCasesVoting } from "./datapoint"; -import { addUserActiveDispute, ensureUser } from "./entities/User"; +import { addUserActiveDispute, computeCoherenceScore, ensureUser } from "./entities/User"; import { updateJurorStake } from "./entities/JurorTokensPerCourt"; import { createDrawFromEvent } from "./entities/Draw"; import { updateTokenAndEthShiftFromEvent } from "./entities/TokenAndEthShift"; @@ -156,8 +156,7 @@ export function handleNewPeriod(event: NewPeriod): void { // Recalculate coherenceScore if (juror.totalResolvedVotes.gt(ZERO)) { - const coherenceScore = juror.totalCoherentVotes.times(BigInt.fromI32(100)).div(juror.totalResolvedVotes); - juror.coherenceScore = coherenceScore; + juror.coherenceScore = computeCoherenceScore(juror.totalCoherentVotes, juror.totalResolvedVotes); } juror.save(); diff --git a/subgraph/core/src/entities/User.ts b/subgraph/core/src/entities/User.ts index dc5932277..f038ad5ac 100644 --- a/subgraph/core/src/entities/User.ts +++ b/subgraph/core/src/entities/User.ts @@ -1,6 +1,20 @@ +import { BigInt, BigDecimal } from "@graphprotocol/graph-ts"; import { User } from "../../generated/schema"; import { ONE, ZERO } from "../utils"; +export function computeCoherenceScore(totalCoherentVotes: BigInt, totalResolvedVotes: BigInt): BigInt { + const smoothingFactor = BigDecimal.fromString("10"); + + let denominator = totalResolvedVotes.toBigDecimal().plus(smoothingFactor); + let coherencyRatio = totalCoherentVotes.toBigDecimal().div(denominator); + + const coherencyScore = coherencyRatio.times(BigDecimal.fromString("100")); + + const roundedScore = coherencyScore.plus(BigDecimal.fromString("0.5")); + + return BigInt.fromString(roundedScore.toString().split(".")[0]); +} + export function ensureUser(id: string): User { const user = User.load(id); diff --git a/subgraph/package.json b/subgraph/package.json index 5beaa8af6..71f1166ef 100644 --- a/subgraph/package.json +++ b/subgraph/package.json @@ -1,6 +1,6 @@ { "name": "@kleros/kleros-v2-subgraph", - "version": "0.7.5", + "version": "0.7.6", "license": "MIT", "scripts": { "update:core:arbitrum-sepolia-devnet": "./scripts/update.sh arbitrumSepoliaDevnet arbitrum-sepolia core/subgraph.yaml", From 38efc1be80472467145585de14588c7fb36d6b10 Mon Sep 17 00:00:00 2001 From: kemuru <102478601+kemuru@users.noreply.github.com> Date: Mon, 7 Oct 2024 13:54:18 +0200 Subject: [PATCH 8/8] fix: readd user test coherence score file --- subgraph/core/tests/user.test.ts | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 subgraph/core/tests/user.test.ts diff --git a/subgraph/core/tests/user.test.ts b/subgraph/core/tests/user.test.ts new file mode 100644 index 000000000..c69548b48 --- /dev/null +++ b/subgraph/core/tests/user.test.ts @@ -0,0 +1,9 @@ +import { assert, test, describe } from "matchstick-as/assembly/index"; +import { BigInt } from "@graphprotocol/graph-ts"; +import { computeCoherenceScore } from "../src/entities/User"; + +describe("Compute coherence score", () => { + test("Slam BigInts together", () => { + assert.bigIntEquals(BigInt.fromI32(8), computeCoherenceScore(BigInt.fromI32(1), BigInt.fromI32(2))); + }); +});