Skip to content

Commit 29aee53

Browse files
authored
Merge pull request #2066 from kleros/feat/contracts-disputekits-helper
Feat: Dispute Kits helper in contracts package
2 parents c8185bd + efb2aad commit 29aee53

File tree

7 files changed

+487
-28
lines changed

7 files changed

+487
-28
lines changed

contracts/CHANGELOG.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,17 @@ All notable changes to this package will be documented in this file.
44

55
The format is based on [Common Changelog](https://common-changelog.org/).
66

7-
## [0.11.0] - 2025-08-01
7+
## [0.12.0] - 2025-08-05
8+
9+
### Changed
10+
11+
- **Breaking:** Make `viem` a peer dependency, it should be provided by the consuming package ([`4594536`](https://github.com/kleros/kleros-v2/commit/4594536c))
12+
13+
### Added
14+
15+
- Add helper function `getDisputeKitsViem` to retrieve a deployment's available dispute kit infos including their capabilities (`isShutter`, `isGated`) ([`5a81f9e`](https://github.com/kleros/kleros-v2/commit/5a81f9ec))
16+
17+
## [0.11.0] - 2025-08-02
818

919
### Changed
1020

@@ -107,6 +117,7 @@ The format is based on [Common Changelog](https://common-changelog.org/).
107117

108118
## [0.8.1] - 2025-04-10
109119

120+
[0.12.0]: https://github.com/kleros/kleros-v2/releases/tag/@kleros%2Fkleros-v2-contracts@0.12.0
110121
[0.11.0]: https://github.com/kleros/kleros-v2/releases/tag/@kleros%2Fkleros-v2-contracts@0.11.0
111122
[0.10.0]: https://github.com/kleros/kleros-v2/releases/tag/@kleros%2Fkleros-v2-contracts@0.10.0
112123
[0.9.4]: https://github.com/kleros/kleros-v2/releases/tag/@kleros%2Fkleros-v2-contracts@0.9.4
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import { getContracts } from "./contractsViem";
2+
import { Abi, AbiEvent, getAbiItem, PublicClient } from "viem";
3+
import { DeploymentName } from "./utils";
4+
5+
export type DisputeKitContracts = ReturnType<typeof getContracts>;
6+
export type DisputeKit =
7+
| NonNullable<DisputeKitContracts["disputeKitClassic"]>
8+
| NonNullable<DisputeKitContracts["disputeKitShutter"]>
9+
| NonNullable<DisputeKitContracts["disputeKitGated"]>
10+
| NonNullable<DisputeKitContracts["disputeKitGatedShutter"]>
11+
| null;
12+
export type DisputeKitInfos = {
13+
address: `0x${string}`;
14+
contract: DisputeKit;
15+
isGated: boolean;
16+
isShutter: boolean;
17+
};
18+
export type DisputeKitByIds = Record<string, DisputeKitInfos>;
19+
20+
const fetchDisputeKits = async (client: PublicClient, klerosCoreAddress: `0x${string}`, klerosCoreAbi: Abi) => {
21+
const DisputeKitCreated = getAbiItem({
22+
abi: klerosCoreAbi,
23+
name: "DisputeKitCreated",
24+
}) as AbiEvent;
25+
const logs = await client.getLogs({
26+
address: klerosCoreAddress,
27+
event: DisputeKitCreated,
28+
fromBlock: 0n,
29+
toBlock: "latest",
30+
});
31+
return Object.fromEntries(
32+
logs
33+
.filter((log) => {
34+
const args = log.args as Record<string, unknown>;
35+
return "_disputeKitID" in args && "_disputeKitAddress" in args;
36+
})
37+
.map((log) => {
38+
const { _disputeKitID, _disputeKitAddress } = log.args as {
39+
_disputeKitID: bigint;
40+
_disputeKitAddress: string;
41+
};
42+
return {
43+
disputeKitID: _disputeKitID,
44+
disputeKitAddress: _disputeKitAddress,
45+
};
46+
})
47+
.map(({ disputeKitID, disputeKitAddress }) => [disputeKitID!.toString(), disputeKitAddress as `0x${string}`])
48+
);
49+
};
50+
51+
export const getDisputeKits = async (client: PublicClient, deployment: DeploymentName): Promise<DisputeKitByIds> => {
52+
const { klerosCore, disputeKitClassic, disputeKitShutter, disputeKitGated, disputeKitGatedShutter } = getContracts({
53+
publicClient: client,
54+
deployment: deployment,
55+
});
56+
57+
const isDefined = <T>(kit: T): kit is NonNullable<T> => kit != null;
58+
const disputeKitContracts = [disputeKitClassic, disputeKitShutter, disputeKitGated, disputeKitGatedShutter].filter(
59+
isDefined
60+
);
61+
const shutterEnabled = [disputeKitShutter, disputeKitGatedShutter].filter(isDefined);
62+
const gatedEnabled = [disputeKitGated, disputeKitGatedShutter].filter(isDefined);
63+
64+
const disputeKitMap = await fetchDisputeKits(client, klerosCore.address, klerosCore.abi);
65+
66+
return Object.fromEntries(
67+
Object.entries(disputeKitMap).map(([disputeKitID, address]) => {
68+
const contract =
69+
disputeKitContracts.find((contract) => contract.address.toLowerCase() === address.toLowerCase()) ?? null;
70+
return [
71+
disputeKitID,
72+
{
73+
address,
74+
contract: contract satisfies DisputeKit,
75+
isGated: contract
76+
? gatedEnabled.some((gated) => contract.address.toLowerCase() === gated.address.toLowerCase())
77+
: false,
78+
isShutter: contract
79+
? shutterEnabled.some((shutter) => contract.address.toLowerCase() === shutter.address.toLowerCase())
80+
: false,
81+
},
82+
];
83+
})
84+
);
85+
};

contracts/deployments/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,6 @@ export * from "./utils";
1717
// Contracts getters
1818
export { getContracts as getContractsEthers } from "./contractsEthers";
1919
export { getContracts as getContractsViem } from "./contractsViem";
20+
21+
// Dispute kits getters
22+
export { getDisputeKits as getDisputeKitsViem, type DisputeKitByIds, type DisputeKitInfos } from "./disputeKitsViem";

contracts/package.json

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@
121121
"@types/mocha": "^10.0.10",
122122
"@types/node": "^20.17.6",
123123
"@types/sinon": "^17.0.4",
124-
"@wagmi/cli": "^2.2.0",
124+
"@wagmi/cli": "^2.3.2",
125125
"abitype": "^0.10.3",
126126
"chai": "^4.5.0",
127127
"dotenv": "^16.6.1",
@@ -157,7 +157,14 @@
157157
"@kleros/vea-contracts": "^0.6.0",
158158
"@openzeppelin/contracts": "^5.4.0",
159159
"@shutter-network/shutter-sdk": "0.0.2",
160-
"isomorphic-fetch": "^3.0.0",
160+
"isomorphic-fetch": "^3.0.0"
161+
},
162+
"peerDependencies": {
161163
"viem": "^2.24.1"
164+
},
165+
"peerDependenciesMeta": {
166+
"viem": {
167+
"optional": false
168+
}
162169
}
163170
}

contracts/scripts/getDisputeKits.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { getDisputeKits } from "../deployments/disputeKitsViem";
2+
import { createPublicClient, http } from "viem";
3+
import { arbitrumSepolia } from "viem/chains";
4+
5+
const rpc = process.env.ARBITRUM_SEPOLIA_RPC;
6+
if (!rpc) {
7+
throw new Error("ARBITRUM_SEPOLIA_RPC is not set");
8+
}
9+
10+
const client = createPublicClient({
11+
chain: arbitrumSepolia,
12+
transport: http(rpc),
13+
});
14+
15+
async function main() {
16+
try {
17+
console.log("Fetching DisputeKitCreated events...");
18+
const disputeKitResult = await getDisputeKits(client, "devnet");
19+
console.log(disputeKitResult);
20+
} catch (error) {
21+
console.error("Error fetching events:", error);
22+
throw error;
23+
}
24+
}
25+
26+
if (require.main === module) {
27+
main()
28+
.then(() => process.exit(0))
29+
.catch((error) => {
30+
console.error(error);
31+
process.exit(1);
32+
});
33+
}

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@
7777
"elliptic@npm:6.5.4": "npm:6.6.1",
7878
"word-wrap@npm:~1.2.3": "npm:1.2.5",
7979
"@codemirror/state": "npm:6.5.2",
80-
"undici@npm:7.3.0": "npm:7.5.0"
80+
"undici@npm:7.3.0": "npm:7.5.0",
81+
"viem@npm:2.x": "npm:^2.23.2"
8182
},
8283
"scripts": {
8384
"check-prerequisites": "scripts/check-prerequisites.sh",

0 commit comments

Comments
 (0)