Skip to content

Commit 2946c1e

Browse files
authored
Merge pull request #2198 from kleros/feat/leaderboard-offset
Feat/leaderboard offset
2 parents 89766af + 94ed78b commit 2946c1e

File tree

13 files changed

+448
-2
lines changed

13 files changed

+448
-2
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { HardhatRuntimeEnvironment } from "hardhat/types";
2+
import { DeployFunction } from "hardhat-deploy/types";
3+
import { HomeChains, isSkipped } from "./utils";
4+
import { getContractOrDeploy } from "./utils/getContractOrDeploy";
5+
6+
const deployLeaderboardOffset: DeployFunction = async (hre: HardhatRuntimeEnvironment) => {
7+
const { getNamedAccounts, getChainId } = hre;
8+
9+
// fallback to hardhat node signers on local network
10+
const deployer = (await getNamedAccounts()).deployer ?? (await hre.ethers.getSigners())[0].address;
11+
const chainId = Number(await getChainId());
12+
console.log("deploying to %s with deployer %s", HomeChains[chainId], deployer);
13+
14+
await getContractOrDeploy(hre, "LeaderboardOffset", {
15+
from: deployer,
16+
args: [deployer],
17+
log: true,
18+
});
19+
};
20+
21+
deployLeaderboardOffset.tags = ["LeaderboardOffset"];
22+
deployLeaderboardOffset.skip = async ({ network }) => {
23+
return isSkipped(network, !HomeChains[network.config.chainId ?? 0]);
24+
};
25+
26+
export default deployLeaderboardOffset;
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
{
2+
"address": "0x811eC94d73445Df262D3Bf43571B85caD122bBD7",
3+
"abi": [
4+
{
5+
"inputs": [
6+
{
7+
"internalType": "address",
8+
"name": "governor_",
9+
"type": "address"
10+
}
11+
],
12+
"stateMutability": "nonpayable",
13+
"type": "constructor"
14+
},
15+
{
16+
"inputs": [],
17+
"name": "InvalidGovernor",
18+
"type": "error"
19+
},
20+
{
21+
"inputs": [],
22+
"name": "NotGovernor",
23+
"type": "error"
24+
},
25+
{
26+
"anonymous": false,
27+
"inputs": [
28+
{
29+
"indexed": true,
30+
"internalType": "address",
31+
"name": "oldGovernor",
32+
"type": "address"
33+
},
34+
{
35+
"indexed": true,
36+
"internalType": "address",
37+
"name": "newGovernor",
38+
"type": "address"
39+
}
40+
],
41+
"name": "GovernorUpdated",
42+
"type": "event"
43+
},
44+
{
45+
"anonymous": false,
46+
"inputs": [
47+
{
48+
"indexed": true,
49+
"internalType": "address",
50+
"name": "user",
51+
"type": "address"
52+
},
53+
{
54+
"indexed": false,
55+
"internalType": "int256",
56+
"name": "offset",
57+
"type": "int256"
58+
},
59+
{
60+
"indexed": true,
61+
"internalType": "address",
62+
"name": "arbitrator",
63+
"type": "address"
64+
}
65+
],
66+
"name": "Offset",
67+
"type": "event"
68+
},
69+
{
70+
"inputs": [],
71+
"name": "governor",
72+
"outputs": [
73+
{
74+
"internalType": "address",
75+
"name": "",
76+
"type": "address"
77+
}
78+
],
79+
"stateMutability": "view",
80+
"type": "function"
81+
},
82+
{
83+
"inputs": [
84+
{
85+
"internalType": "address",
86+
"name": "juror",
87+
"type": "address"
88+
},
89+
{
90+
"internalType": "int256",
91+
"name": "offset",
92+
"type": "int256"
93+
},
94+
{
95+
"internalType": "address",
96+
"name": "arbitrator",
97+
"type": "address"
98+
}
99+
],
100+
"name": "setOffset",
101+
"outputs": [],
102+
"stateMutability": "nonpayable",
103+
"type": "function"
104+
},
105+
{
106+
"inputs": [
107+
{
108+
"internalType": "address",
109+
"name": "newGovernor",
110+
"type": "address"
111+
}
112+
],
113+
"name": "updateGovernor",
114+
"outputs": [],
115+
"stateMutability": "nonpayable",
116+
"type": "function"
117+
}
118+
],
119+
"transactionHash": "0xbb59c3799cd0cdb002ab5d50a73ce4df0f7a31a6da376d35d651695c4c035553",
120+
"receipt": {
121+
"to": null,
122+
"from": "0x88AB19C0c7b57EeBa545acbD4368748194cd796B",
123+
"contractAddress": "0x811eC94d73445Df262D3Bf43571B85caD122bBD7",
124+
"transactionIndex": 4,
125+
"gasUsed": "188293",
126+
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
127+
"blockHash": "0x1eda1fac08593a4d20c0da0b64d5c6608e59100b9e7f928142175bf7ab2b1807",
128+
"transactionHash": "0xbb59c3799cd0cdb002ab5d50a73ce4df0f7a31a6da376d35d651695c4c035553",
129+
"logs": [],
130+
"blockNumber": 217101551,
131+
"cumulativeGasUsed": "583258",
132+
"status": 1,
133+
"byzantium": true
134+
},
135+
"args": [
136+
"0x88AB19C0c7b57EeBa545acbD4368748194cd796B"
137+
],
138+
"numDeployments": 1,
139+
"solcInputHash": "5b02862a3326bb805f178280f9f88e2d",
140+
"metadata": "{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"governor_\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InvalidGovernor\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotGovernor\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oldGovernor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"GovernorUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"offset\",\"type\":\"int256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"arbitrator\",\"type\":\"address\"}],\"name\":\"Offset\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"governor\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"juror\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"offset\",\"type\":\"int256\"},{\"internalType\":\"address\",\"name\":\"arbitrator\",\"type\":\"address\"}],\"name\":\"setOffset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newGovernor\",\"type\":\"address\"}],\"name\":\"updateGovernor\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"setOffset(address,int256,address)\":{\"params\":{\"arbitrator\":\"The arbitrator address.\",\"juror\":\"The address of the affected juror.\",\"offset\":\"The signed integer offset (+ or -).\"}},\"updateGovernor(address)\":{\"params\":{\"newGovernor\":\"The new governor address.\"}}},\"title\":\"LeaderboardOffset\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"setOffset(address,int256,address)\":{\"notice\":\"Emits an offset event for a given juror.\"},\"updateGovernor(address)\":{\"notice\":\"Updates the governor address.\"}},\"notice\":\"Emits event to offset juror score for coherency\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/governance/LeaderboardOffset.sol\":\"LeaderboardOffset\"},\"evmVersion\":\"cancun\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":850},\"remappings\":[],\"viaIR\":true},\"sources\":{\"src/governance/LeaderboardOffset.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.28;\\n\\n/**\\n * @title LeaderboardOffset\\n * @notice Emits event to offset juror score for coherency\\n */\\ncontract LeaderboardOffset {\\n // ************************************* //\\n // * Events * //\\n // ************************************* //\\n event Offset(address indexed user, int256 offset, address indexed arbitrator);\\n\\n event GovernorUpdated(address indexed oldGovernor, address indexed newGovernor);\\n\\n // ************************************* //\\n // * Storage * //\\n // ************************************* //\\n\\n address public governor;\\n\\n // ************************************* //\\n // * Constructor * //\\n // ************************************* //\\n constructor(address governor_) {\\n if (governor_ == address(0)) revert InvalidGovernor();\\n governor = governor_;\\n }\\n\\n // ************************************* //\\n // * Function Modifiers * //\\n // ************************************* //\\n modifier onlyGovernor() {\\n if (msg.sender != governor) revert NotGovernor();\\n _;\\n }\\n\\n // ************************************* //\\n // * Governance * //\\n // ************************************* //\\n\\n /**\\n * @notice Emits an offset event for a given juror.\\n * @param juror The address of the affected juror.\\n * @param offset The signed integer offset (+ or -).\\n * @param arbitrator The arbitrator address.\\n */\\n function setOffset(address juror, int256 offset, address arbitrator) external onlyGovernor {\\n emit Offset(juror, offset, arbitrator);\\n }\\n\\n /**\\n * @notice Updates the governor address.\\n * @param newGovernor The new governor address.\\n */\\n function updateGovernor(address newGovernor) external onlyGovernor {\\n if (newGovernor == address(0)) revert InvalidGovernor();\\n\\n emit GovernorUpdated(governor, newGovernor);\\n governor = newGovernor;\\n }\\n\\n // ************************************* //\\n // * Errors * //\\n // ************************************* //\\n error NotGovernor();\\n error InvalidGovernor();\\n}\\n\",\"keccak256\":\"0x902182a029a64bf2fa34d2ec8a8ed887e951b25325c9e43afdf5eba08dca5521\",\"license\":\"MIT\"}},\"version\":1}",
141+
"bytecode": "0x608034608357601f61029e38819003918201601f19168301916001600160401b03831184841017608757808492602094604052833981010312608357516001600160a01b0381169081900360835780156074575f80546001600160a01b031916919091179055604051610202908161009c8239f35b636630f75560e11b5f5260045ffd5b5f80fd5b634e487b7160e01b5f52604160045260245ffdfe6080806040526004361015610012575f80fd5b5f3560e01c9081630c340a24146101945750806362f384ad146100e15763d5c002611461003d575f80fd5b346100dd5760603660031901126100dd576100566101b6565b604435906001600160a01b0382168092036100dd576001600160a01b035f541633036100b5577ffa924885f0d4e35a861265635470acad0f0bd25cabcc09fcde0c0f07aaa0d3e260206001600160a01b036040519360243585521692a3005b7fee3675d4000000000000000000000000000000000000000000000000000000005f5260045ffd5b5f80fd5b346100dd5760203660031901126100dd576100fa6101b6565b5f54906001600160a01b038216908133036100b5576001600160a01b031691821561016c57827fffffffffffffffffffffffff0000000000000000000000000000000000000000927f5af6a85e864342d4f108c43dd574d98480c91f1de0ac2a9f66d826dee49bd9bb5f80a316175f55005b7fcc61eeaa000000000000000000000000000000000000000000000000000000005f5260045ffd5b346100dd575f3660031901126100dd576020906001600160a01b035f54168152f35b600435906001600160a01b03821682036100dd5756fea2646970667358221220c134b6c3d9ae5644bb802d1fd43d4318cdef95997eaa60d5389c777c3918dcba64736f6c634300081e0033",
142+
"deployedBytecode": "0x6080806040526004361015610012575f80fd5b5f3560e01c9081630c340a24146101945750806362f384ad146100e15763d5c002611461003d575f80fd5b346100dd5760603660031901126100dd576100566101b6565b604435906001600160a01b0382168092036100dd576001600160a01b035f541633036100b5577ffa924885f0d4e35a861265635470acad0f0bd25cabcc09fcde0c0f07aaa0d3e260206001600160a01b036040519360243585521692a3005b7fee3675d4000000000000000000000000000000000000000000000000000000005f5260045ffd5b5f80fd5b346100dd5760203660031901126100dd576100fa6101b6565b5f54906001600160a01b038216908133036100b5576001600160a01b031691821561016c57827fffffffffffffffffffffffff0000000000000000000000000000000000000000927f5af6a85e864342d4f108c43dd574d98480c91f1de0ac2a9f66d826dee49bd9bb5f80a316175f55005b7fcc61eeaa000000000000000000000000000000000000000000000000000000005f5260045ffd5b346100dd575f3660031901126100dd576020906001600160a01b035f54168152f35b600435906001600160a01b03821682036100dd5756fea2646970667358221220c134b6c3d9ae5644bb802d1fd43d4318cdef95997eaa60d5389c777c3918dcba64736f6c634300081e0033",
143+
"devdoc": {
144+
"kind": "dev",
145+
"methods": {
146+
"setOffset(address,int256,address)": {
147+
"params": {
148+
"arbitrator": "The arbitrator address.",
149+
"juror": "The address of the affected juror.",
150+
"offset": "The signed integer offset (+ or -)."
151+
}
152+
},
153+
"updateGovernor(address)": {
154+
"params": {
155+
"newGovernor": "The new governor address."
156+
}
157+
}
158+
},
159+
"title": "LeaderboardOffset",
160+
"version": 1
161+
},
162+
"userdoc": {
163+
"kind": "user",
164+
"methods": {
165+
"setOffset(address,int256,address)": {
166+
"notice": "Emits an offset event for a given juror."
167+
},
168+
"updateGovernor(address)": {
169+
"notice": "Updates the governor address."
170+
}
171+
},
172+
"notice": "Emits event to offset juror score for coherency",
173+
"version": 1
174+
},
175+
"storageLayout": {
176+
"storage": [
177+
{
178+
"astId": 18,
179+
"contract": "src/governance/LeaderboardOffset.sol:LeaderboardOffset",
180+
"label": "governor",
181+
"offset": 0,
182+
"slot": "0",
183+
"type": "t_address"
184+
}
185+
],
186+
"types": {
187+
"t_address": {
188+
"encoding": "inplace",
189+
"label": "address",
190+
"numberOfBytes": "20"
191+
}
192+
}
193+
}
194+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.28;
3+
4+
/**
5+
* @title LeaderboardOffset
6+
* @notice Emits event to offset juror score for coherency
7+
*/
8+
contract LeaderboardOffset {
9+
// ************************************* //
10+
// * Events * //
11+
// ************************************* //
12+
event Offset(address indexed user, int256 offset, address indexed arbitrator);
13+
14+
event GovernorUpdated(address indexed oldGovernor, address indexed newGovernor);
15+
16+
// ************************************* //
17+
// * Storage * //
18+
// ************************************* //
19+
20+
address public governor;
21+
22+
// ************************************* //
23+
// * Constructor * //
24+
// ************************************* //
25+
constructor(address governor_) {
26+
if (governor_ == address(0)) revert InvalidGovernor();
27+
governor = governor_;
28+
}
29+
30+
// ************************************* //
31+
// * Function Modifiers * //
32+
// ************************************* //
33+
modifier onlyGovernor() {
34+
if (msg.sender != governor) revert NotGovernor();
35+
_;
36+
}
37+
38+
// ************************************* //
39+
// * Governance * //
40+
// ************************************* //
41+
42+
/**
43+
* @notice Emits an offset event for a given juror.
44+
* @param juror The address of the affected juror.
45+
* @param offset The signed integer offset (+ or -).
46+
* @param arbitrator The arbitrator address.
47+
*/
48+
function setOffset(address juror, int256 offset, address arbitrator) external onlyGovernor {
49+
emit Offset(juror, offset, arbitrator);
50+
}
51+
52+
/**
53+
* @notice Updates the governor address.
54+
* @param newGovernor The new governor address.
55+
*/
56+
function updateGovernor(address newGovernor) external onlyGovernor {
57+
if (newGovernor == address(0)) revert InvalidGovernor();
58+
59+
emit GovernorUpdated(governor, newGovernor);
60+
governor = newGovernor;
61+
}
62+
63+
// ************************************* //
64+
// * Errors * //
65+
// ************************************* //
66+
error NotGovernor();
67+
error InvalidGovernor();
68+
}

subgraph/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.bin
2+
*.wasm
3+
.latest.json

subgraph/core/schema.graphql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ type User @entity {
7979
totalCoherentVotes: BigInt!
8080
totalResolvedVotes: BigInt!
8181
coherenceScore: BigInt!
82+
leaderboardOffset: BigInt!
8283
votes: [Vote!]! @derivedFrom(field: "juror")
8384
contributions: [Contribution!]! @derivedFrom(field: "contributor")
8485
evidences: [ClassicEvidence!]! @derivedFrom(field: "sender")
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { log } from "@graphprotocol/graph-ts";
2+
import { Offset } from "../generated/LeaderboardOffset/LeaderboardOffset";
3+
import { User } from "../generated/schema";
4+
import { computeCoherenceScore } from "./entities/User";
5+
6+
export function handleLeaderboardOffset(event: Offset): void {
7+
const user = User.load(event.params.user.toHexString());
8+
if (!user) {
9+
log.error(`User {} not found.`, [event.params.user.toHexString()]);
10+
return;
11+
}
12+
//keep track of offset separately
13+
user.leaderboardOffset = user.leaderboardOffset.plus(event.params.offset);
14+
15+
//apply the offset and re compute coherenceScore
16+
user.totalCoherentVotes = user.totalCoherentVotes.plus(event.params.offset);
17+
// Recalculate coherenceScore
18+
user.coherenceScore = computeCoherenceScore(user.totalCoherentVotes, user.totalResolvedVotes);
19+
20+
user.save();
21+
}

subgraph/core/src/entities/User.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export function createUserFromAddress(id: string): User {
4040
user.totalCoherentVotes = ZERO;
4141
user.totalResolvedVotes = ZERO;
4242
user.coherenceScore = ZERO;
43+
user.leaderboardOffset = ZERO;
4344
user.save();
4445

4546
return user;

subgraph/core/subgraph.template.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,3 +273,23 @@ dataSources:
273273
- event: StakeSet(indexed address,uint256,uint256,uint256)
274274
handler: handleStakeSet
275275
file: ./src/SortitionModule.ts
276+
- kind: ethereum
277+
name: LeaderboardOffset
278+
network: _PLACEHOLDER_
279+
source:
280+
address: "_PLACEHOLDER_"
281+
abi: LeaderboardOffset
282+
startBlock: _PLACEHOLDER_
283+
mapping:
284+
kind: ethereum/events
285+
apiVersion: 0.0.7
286+
language: wasm/assemblyscript
287+
entities:
288+
- User
289+
abis:
290+
- name: LeaderboardOffset
291+
file: ../../contracts/deployments/_PLACEHOLDER_/LeaderboardOffset.json
292+
eventHandlers:
293+
- event: Offset(indexed address,int256,indexed address)
294+
handler: handleLeaderboardOffset
295+
file: ./src/LeaderboardOffset.ts

subgraph/core/subgraph.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,3 +274,23 @@ dataSources:
274274
- event: StakeSet(indexed address,uint256,uint256,uint256)
275275
handler: handleStakeSet
276276
file: ./src/SortitionModule.ts
277+
- kind: ethereum
278+
name: LeaderboardOffset
279+
network: arbitrum-sepolia
280+
source:
281+
address: "0x811eC94d73445Df262D3Bf43571B85caD122bBD7"
282+
abi: LeaderboardOffset
283+
startBlock: 217101551
284+
mapping:
285+
kind: ethereum/events
286+
apiVersion: 0.0.7
287+
language: wasm/assemblyscript
288+
entities:
289+
- User
290+
abis:
291+
- name: LeaderboardOffset
292+
file: ../../contracts/deployments/arbitrumSepoliaDevnet/LeaderboardOffset.json
293+
eventHandlers:
294+
- event: Offset(indexed address,int256,indexed address)
295+
handler: handleLeaderboardOffset
296+
file: ./src/LeaderboardOffset.ts

0 commit comments

Comments
 (0)