Skip to content

Commit 708a6b5

Browse files
committed
Merge branch 'master' into feat(web)/dashboard-page
2 parents 945bc18 + 820209d commit 708a6b5

File tree

7 files changed

+111
-17
lines changed

7 files changed

+111
-17
lines changed

contracts/src/arbitration/KlerosCore.sol

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -823,8 +823,9 @@ contract KlerosCore is IArbitrator {
823823

824824
// Unstake the juror if he lost due to inactivity.
825825
if (!disputeKit.isVoteActive(_disputeID, _round, i)) {
826-
for (uint256 j = 0; j < jurors[account].subcourtIDs.length; j++) {
827-
setStakeForAccount(account, jurors[account].subcourtIDs[j], 0, 0);
826+
uint96[] memory subcourtIDs = getJurorSubcourtIDs(account);
827+
for (uint256 j = 0; j < subcourtIDs.length; j++) {
828+
setStakeForAccount(account, subcourtIDs[j], 0, 0);
828829
}
829830
}
830831
emit TokenAndETHShift(account, _disputeID, -int256(penalty), 0);
@@ -1064,6 +1065,10 @@ contract KlerosCore is IArbitrator {
10641065
return disputesKitIDsThatNeedFreezing;
10651066
}
10661067

1068+
function getJurorSubcourtIDs(address _juror) public view returns (uint96[] memory) {
1069+
return jurors[_juror].subcourtIDs;
1070+
}
1071+
10671072
// ************************************* //
10681073
// * Internal * //
10691074
// ************************************* //

contracts/src/bridge/FastBridgeReceiverOnEthereum.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ contract FastBridgeReceiverOnEthereum is IFastBridgeReceiver, ISafeBridgeReceive
117117

118118
uint256 epochNow = block.timestamp / epochPeriod;
119119
// allow claim about current or previous epoch
120-
require(_epoch == epochNow || _epoch == epochNow + 1, "Invalid Claim");
120+
require(_epoch == epochNow || _epoch == epochNow + 1, "Invalid epoch.");
121121
require(claims[_epoch].bridger == address(0), "Claim already made for most recent finalized epoch.");
122122

123123
claims[_epoch] = Claim({

contracts/src/bridge/FastBridgeReceiverOnGnosis.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ contract FastBridgeReceiverOnGnosis is IFastBridgeReceiver, ISafeBridgeReceiver
115115

116116
uint256 epochNow = block.timestamp / epochPeriod;
117117
// allow claim about current or previous epoch
118-
require(_epoch == epochNow || _epoch == epochNow + 1, "Invalid Claim");
118+
require(_epoch == epochNow || _epoch == epochNow + 1, "Invalid Epoch.");
119119
require(claims[_epoch].bridger == address(0), "Claim already made for most recent finalized epoch.");
120120

121121
claims[_epoch] = Claim({

contracts/src/bridge/FastBridgeReceiverOnPolygon.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ contract FastBridgeReceiverOnPolygon is FxBaseChildTunnel, IFastBridgeReceiver,
109109

110110
uint256 epochNow = block.timestamp / epochPeriod;
111111
// allow claim about current or previous epoch
112-
require(_epoch == epochNow || _epoch == epochNow + 1, "Invalid Claim");
112+
require(_epoch == epochNow || _epoch == epochNow + 1, "Invalid Epoch");
113113
require(claims[_epoch].bridger == address(0), "Claim already made for most recent finalized epoch.");
114114

115115
claims[_epoch] = Claim({

contracts/test/arbitration/unstake.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { ethers, getNamedAccounts, network, deployments } from "hardhat";
2+
import { BigNumber } from "ethers";
3+
import { PNK, KlerosCore, DisputeKitClassic } from "../../typechain-types";
4+
import { expect } from "chai";
5+
6+
/* eslint-disable no-unused-vars */
7+
/* eslint-disable no-unused-expressions */
8+
9+
describe("Unstake juror", async () => {
10+
const ONE_TENTH_ETH = BigNumber.from(10).pow(17);
11+
const ONE_THOUSAND_PNK = BigNumber.from(10).pow(21);
12+
13+
// 2nd court, 3 jurors, 1 dispute kit
14+
const extraData =
15+
"0x000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000001";
16+
17+
let deployer;
18+
let disputeKit;
19+
let pnk;
20+
let core;
21+
22+
beforeEach("Setup", async () => {
23+
({ deployer } = await getNamedAccounts());
24+
25+
console.log("deployer:%s", deployer);
26+
console.log("named accounts: %O", await getNamedAccounts());
27+
28+
await deployments.fixture(["Arbitration"], {
29+
fallbackToGlobal: true,
30+
keepExistingDeployments: false,
31+
});
32+
disputeKit = (await ethers.getContract("DisputeKitClassic")) as DisputeKitClassic;
33+
pnk = (await ethers.getContract("PNK")) as PNK;
34+
core = (await ethers.getContract("KlerosCore")) as KlerosCore;
35+
});
36+
37+
it("Unstake inactive juror", async () => {
38+
const arbitrationCost = ONE_TENTH_ETH.mul(3);
39+
40+
await core.createSubcourt(1, false, ONE_THOUSAND_PNK, 1000, ONE_TENTH_ETH, 3, [0, 0, 0, 0], 3, [1]); // Parent - general court, Classic dispute kit
41+
42+
await pnk.approve(core.address, ONE_THOUSAND_PNK.mul(4));
43+
await core.setStake(1, ONE_THOUSAND_PNK.mul(2));
44+
await core.setStake(2, ONE_THOUSAND_PNK.mul(2));
45+
46+
expect(await core.getJurorSubcourtIDs(deployer)).to.be.deep.equal([BigNumber.from("1"), BigNumber.from("2")]);
47+
48+
await core.createDispute(2, extraData, { value: arbitrationCost });
49+
50+
await network.provider.send("evm_increaseTime", [130]); // Wait for minStakingTime
51+
await network.provider.send("evm_mine");
52+
await core.passPhase(); // Staking -> Freezing
53+
54+
for (let index = 0; index < 20; index++) {
55+
await network.provider.send("evm_mine"); // Wait for 20 blocks finality
56+
}
57+
await disputeKit.passPhase(); // Resolving -> Generating
58+
await disputeKit.passPhase(); // Generating -> Drawing
59+
60+
await core.draw(0, 5000);
61+
62+
await disputeKit.passPhase(); // Drawing -> Resolving
63+
64+
await core.passPeriod(0); // Evidence -> Voting
65+
await core.passPeriod(0); // Voting -> Appeal
66+
await core.passPeriod(0); // Appeal -> Execution
67+
68+
await core.passPhase(); // Freezing -> Staking. Change so we don't deal with delayed stakes
69+
70+
expect(await core.getJurorSubcourtIDs(deployer)).to.be.deep.equal([BigNumber.from("1"), BigNumber.from("2")]);
71+
72+
await core.execute(0, 0, 1); // 1 iteration should unstake from both courts
73+
74+
expect(await core.getJurorSubcourtIDs(deployer)).to.be.deep.equal([]);
75+
});
76+
});

web/src/hooks/useHomePageContext.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@ interface IContext {
88
isValidating: boolean;
99
}
1010

11+
export type HomePageQueryDataPoints =
12+
| HomePageQuery["pnkstakedDataPoints"]
13+
| HomePageQuery["pnkredistributedDataPoints"]
14+
| HomePageQuery["casesDataPoints"]
15+
| HomePageQuery["ethpaidDataPoints"]
16+
| HomePageQuery["activeJurorsDataPoints"];
17+
1118
const Context = createContext<IContext>({
1219
data: undefined,
1320
error: null,

web/src/pages/Home/CourtOverview/Stats.tsx

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
import React from "react";
22
import styled from "styled-components";
3-
import { utils } from "ethers";
3+
import { utils, BigNumber } from "ethers";
44
import { Card } from "@kleros/ui-components-library";
55
import StatDisplay, { IStatDisplay } from "components/StatDisplay";
66
import PNKIcon from "svgs/icons/pnk.svg";
77
import EthereumIcon from "svgs/icons/ethereum.svg";
88
import PNKRedistributedIcon from "svgs/icons/redistributed-pnk.svg";
99
import JurorIcon from "svgs/icons/user.svg";
1010
import BalanceIcon from "svgs/icons/law-balance.svg";
11-
import { useHomePageContext, HomePageQuery } from "hooks/useHomePageContext";
11+
import {
12+
useHomePageContext,
13+
HomePageQuery,
14+
HomePageQueryDataPoints,
15+
} from "hooks/useHomePageContext";
1216

1317
const StyledCard = styled(Card)`
1418
width: auto;
@@ -21,6 +25,9 @@ const StyledCard = styled(Card)`
2125
flex-wrap: wrap;
2226
`;
2327

28+
const getLastOrZero = (src: HomePageQueryDataPoints) =>
29+
src.length > 0 ? src.at(-1)?.value : BigNumber.from(0).toString();
30+
2431
interface IStat {
2532
title: string;
2633
getText: (data: HomePageQuery) => string;
@@ -32,42 +39,41 @@ interface IStat {
3239
const stats: IStat[] = [
3340
{
3441
title: "PNK staked",
35-
getText: (data) =>
36-
utils.commify(
37-
utils.formatUnits(data?.pnkstakedDataPoints.at(-1)?.value, 18)
38-
),
42+
getText: ({ pnkstakedDataPoints }) =>
43+
utils.commify(utils.formatUnits(getLastOrZero(pnkstakedDataPoints), 18)),
3944
getSubtext: () => "$ 3 000 000",
4045
color: "purple",
4146
icon: PNKIcon,
4247
},
4348
{
4449
title: "ETH Paid to jurors",
45-
getText: (data) =>
46-
utils.commify(utils.formatEther(data?.ethpaidDataPoints.at(-1)?.value)),
50+
getText: ({ ethpaidDataPoints }) =>
51+
utils.commify(utils.formatEther(getLastOrZero(ethpaidDataPoints))),
4752
getSubtext: () => "$ 3,000,000",
4853
color: "blue",
4954
icon: EthereumIcon,
5055
},
5156
{
5257
title: "PNK redistributed",
53-
getText: (data) =>
58+
getText: ({ pnkredistributedDataPoints }) =>
5459
utils.commify(
55-
utils.formatUnits(data?.pnkredistributedDataPoints.at(-1)?.value, 18)
60+
utils.formatUnits(getLastOrZero(pnkredistributedDataPoints), 18)
5661
),
5762
getSubtext: () => "$ 3,000,000",
5863
color: "purple",
5964
icon: PNKRedistributedIcon,
6065
},
6166
{
6267
title: "Active jurors",
63-
getText: (data) => data?.activeJurorsDataPoints.at(-1)?.value,
68+
getText: ({ activeJurorsDataPoints }) =>
69+
getLastOrZero(activeJurorsDataPoints),
6470
getSubtext: () => "$ 3,000,000",
6571
color: "green",
6672
icon: JurorIcon,
6773
},
6874
{
6975
title: "Cases",
70-
getText: (data) => data?.casesDataPoints.at(-1)?.value,
76+
getText: ({ casesDataPoints }) => getLastOrZero(casesDataPoints),
7177
getSubtext: () => "$ 3,000,000",
7278
color: "orange",
7379
icon: BalanceIcon,

0 commit comments

Comments
 (0)