Skip to content

Commit ccd375a

Browse files
authored
Merge branch 'fix(web)/staking-refetch-and-improving-fetching-timing' into feat(web)/various-info-popups
2 parents 26b2cb6 + a7ee03e commit ccd375a

File tree

12 files changed

+223
-58
lines changed

12 files changed

+223
-58
lines changed

subgraph/schema.graphql

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,11 @@ type TokenAndETHShift @entity {
9696
id: ID! # user.id-dispute.id
9797
juror: User!
9898
dispute: Dispute!
99-
tokenAmount: BigInt!
99+
pnkAmount: BigInt!
100100
ethAmount: BigInt!
101+
isNativeCurrency: Boolean!
102+
feeTokenAmount: BigInt!
103+
feeToken: FeeToken
101104
}
102105

103106
type JurorTokensPerCourt @entity {
@@ -159,6 +162,7 @@ type Round @entity {
159162
penalties: BigInt!
160163
drawnJurors: [Draw!]! @derivedFrom(field: "round")
161164
dispute: Dispute!
165+
feeToken: FeeToken
162166
}
163167

164168
type Draw @entity {
@@ -191,6 +195,17 @@ type Counter @entity {
191195
casesRuled: BigInt!
192196
}
193197

198+
type FeeToken @entity {
199+
id: ID! # The address of the ERC20 token.
200+
accepted: Boolean!
201+
rateInEth: BigInt!
202+
rateDecimals: Int!
203+
totalPaid: BigInt!
204+
totalPaidInETH: BigInt!
205+
rounds: [Round!] @derivedFrom(field: "feeToken")
206+
tokenAndETHShift: [TokenAndETHShift!] @derivedFrom(field: "feeToken")
207+
}
208+
194209
#####################
195210
# ClassicDisputeKit #
196211
#####################

subgraph/src/KlerosCore.ts

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,23 @@ import {
1212
TokenAndETHShift as TokenAndETHShiftEvent,
1313
Ruling,
1414
StakeDelayed,
15+
AcceptedFeeToken,
1516
} from "../generated/KlerosCore/KlerosCore";
1617
import { ZERO, ONE } from "./utils";
1718
import { createCourtFromEvent, getFeeForJuror } from "./entities/Court";
1819
import { createDisputeKitFromEvent, filterSupportedDisputeKits } from "./entities/DisputeKit";
1920
import { createDisputeFromEvent } from "./entities/Dispute";
2021
import { createRoundFromRoundInfo } from "./entities/Round";
21-
import { updateCases, updatePaidETH, updateRedistributedPNK, updateCasesRuled, updateCasesVoting } from "./datapoint";
22+
import { updateCases, updateCasesRuled, updateCasesVoting } from "./datapoint";
2223
import { addUserActiveDispute, ensureUser } from "./entities/User";
2324
import { updateJurorDelayedStake, updateJurorStake } from "./entities/JurorTokensPerCourt";
2425
import { createDrawFromEvent } from "./entities/Draw";
2526
import { updateTokenAndEthShiftFromEvent } from "./entities/TokenAndEthShift";
2627
import { updateArbitrableCases } from "./entities/Arbitrable";
27-
import { Court, Dispute } from "../generated/schema";
28+
import { Court, Dispute, FeeToken } from "../generated/schema";
2829
import { BigInt } from "@graphprotocol/graph-ts";
2930
import { updatePenalty } from "./entities/Penalty";
31+
import { ensureFeeToken } from "./entities/FeeToken";
3032

3133
function getPeriodName(index: i32): string {
3234
const periodArray = ["evidence", "commit", "vote", "appeal", "execution"];
@@ -156,22 +158,17 @@ export function handleStakeDelayed(event: StakeDelayed): void {
156158
}
157159

158160
export function handleTokenAndETHShift(event: TokenAndETHShiftEvent): void {
161+
updatePenalty(event);
159162
updateTokenAndEthShiftFromEvent(event);
160163
const jurorAddress = event.params._account.toHexString();
161164
const disputeID = event.params._disputeID.toString();
162-
const pnkAmount = event.params._pnkAmount;
163-
const feeAmount = event.params._feeAmount;
164165
const dispute = Dispute.load(disputeID);
165166
if (!dispute) return;
166167
const court = Court.load(dispute.court);
167168
if (!court) return;
168169
updateJurorStake(jurorAddress, court.id, KlerosCore.bind(event.address), event.block.timestamp);
169-
court.paidETH = court.paidETH.plus(feeAmount);
170-
if (pnkAmount.gt(ZERO)) {
171-
court.paidPNK = court.paidPNK.plus(pnkAmount);
172-
updateRedistributedPNK(pnkAmount, event.block.timestamp);
173-
}
174-
updatePaidETH(feeAmount, event.block.timestamp);
175-
updatePenalty(event);
176-
court.save();
170+
}
171+
172+
export function handleAcceptedFeeToken(event: AcceptedFeeToken): void {
173+
ensureFeeToken(event.params._token, event.address);
177174
}

subgraph/src/entities/FeeToken.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { BigInt, Address } from "@graphprotocol/graph-ts";
2+
import { FeeToken } from "../../generated/schema";
3+
import { KlerosCore } from "../../generated/KlerosCore/KlerosCore";
4+
import { ZERO } from "../utils";
5+
6+
export function ensureFeeToken(tokenAddress: Address, klerosCoreAddress: Address): FeeToken {
7+
const hexTokenAddress = tokenAddress.toHexString();
8+
let feeToken = FeeToken.load(hexTokenAddress);
9+
if (!feeToken) {
10+
feeToken = new FeeToken(hexTokenAddress);
11+
feeToken.totalPaid = ZERO;
12+
feeToken.totalPaidInETH = ZERO;
13+
}
14+
const contract = KlerosCore.bind(klerosCoreAddress);
15+
const currencyRate = contract.currencyRates(tokenAddress);
16+
feeToken.accepted = currencyRate.value0;
17+
feeToken.rateInEth = currencyRate.value1;
18+
feeToken.rateDecimals = currencyRate.value2;
19+
feeToken.save();
20+
return feeToken;
21+
}
22+
23+
export function updateFeeTokenRate(tokenAddress: Address, klerosCoreAddress: Address): void {
24+
const feeToken = ensureFeeToken(tokenAddress, klerosCoreAddress);
25+
const contract = KlerosCore.bind(klerosCoreAddress);
26+
const currencyRate = contract.currencyRates(tokenAddress);
27+
feeToken.accepted = currencyRate.value0;
28+
feeToken.rateInEth = currencyRate.value1;
29+
feeToken.rateDecimals = currencyRate.value2;
30+
feeToken.save();
31+
}
32+
33+
export function updateFeeTokenPaid(tokenAddress: Address, klerosCoreAddress: Address, amount: BigInt): void {
34+
const feeToken = ensureFeeToken(tokenAddress, klerosCoreAddress);
35+
const ethAmount = convertTokenAmountToEth(tokenAddress, amount, klerosCoreAddress);
36+
feeToken.totalPaid = feeToken.totalPaid.plus(amount);
37+
feeToken.totalPaidInETH = feeToken.totalPaidInETH.plus(ethAmount);
38+
feeToken.save();
39+
}
40+
41+
export function convertEthToTokenAmount(tokenAddress: Address, eth: BigInt, klerosCoreAddress: Address): BigInt {
42+
const feeToken = ensureFeeToken(tokenAddress, klerosCoreAddress);
43+
return eth.times(BigInt.fromI32(10 ** feeToken.rateDecimals)).div(feeToken.rateInEth);
44+
}
45+
46+
export function convertTokenAmountToEth(
47+
tokenAddress: Address,
48+
tokenAmount: BigInt,
49+
klerosCoreAddress: Address
50+
): BigInt {
51+
const feeToken = ensureFeeToken(tokenAddress, klerosCoreAddress);
52+
return tokenAmount.times(feeToken.rateInEth).div(BigInt.fromI32(10 ** feeToken.rateDecimals));
53+
}

subgraph/src/entities/Round.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,15 @@ export function createRoundFromRoundInfo(
99
): void {
1010
const roundID = `${disputeID.toString()}-${roundIndex.toString()}`;
1111
const round = new Round(roundID);
12+
const feeToken = roundInfo.getFeeToken();
1213
round.disputeKit = roundInfo.getDisputeKitID.toString();
1314
round.tokensAtStakePerJuror = roundInfo.getPnkAtStakePerJuror();
1415
round.totalFeesForJurors = roundInfo.getTotalFeesForJurors();
1516
round.nbVotes = roundInfo.getNbVotes();
1617
round.repartitions = roundInfo.getRepartitions();
1718
round.penalties = roundInfo.getPnkPenalties();
1819
round.dispute = disputeID.toString();
20+
round.feeToken =
21+
feeToken.toHexString() === "0x0000000000000000000000000000000000000000" ? null : feeToken.toHexString();
1922
round.save();
2023
}
Lines changed: 58 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,68 @@
1+
import { Address, BigInt } from "@graphprotocol/graph-ts";
12
import { TokenAndETHShift as TokenAndETHShiftEvent } from "../../generated/KlerosCore/KlerosCore";
2-
import { TokenAndETHShift } from "../../generated/schema";
3+
import { Court, Dispute, TokenAndETHShift } from "../../generated/schema";
4+
import { updatePaidETH, updateRedistributedPNK } from "../datapoint";
35
import { ZERO } from "../utils";
6+
import { convertTokenAmountToEth, updateFeeTokenPaid } from "./FeeToken";
47
import { resolveUserDispute } from "./User";
58

69
export function updateTokenAndEthShiftFromEvent(event: TokenAndETHShiftEvent): void {
7-
const jurorAddress = event.params._account.toHexString();
8-
const disputeID = event.params._disputeID.toString();
9-
const shiftID = `${jurorAddress}-${disputeID}`;
10-
const shift = TokenAndETHShift.load(shiftID);
11-
12-
if (!shift) {
13-
createTokenAndEthShiftFromEvent(event);
14-
resolveUserDispute(jurorAddress, ZERO, event.params._feeAmount, disputeID);
15-
return;
10+
const jurorAddress = event.params._account;
11+
const disputeID = event.params._disputeID;
12+
const dispute = Dispute.load(disputeID.toString());
13+
if (!dispute) return;
14+
const court = Court.load(dispute.court);
15+
if (!court) return;
16+
const roundIndex = event.params._roundID;
17+
const feeTokenAddress = event.params._feeToken;
18+
let shift = ensureTokenAndEthShift(jurorAddress, disputeID, roundIndex, feeTokenAddress);
19+
const feeAmount = event.params._feeAmount;
20+
const pnkAmount = event.params._pnkAmount;
21+
let ethAmount: BigInt;
22+
if (feeTokenAddress.toHexString() === "0x0000000000000000000000000000000000000000") {
23+
updateFeeTokenPaid(feeTokenAddress, event.address, feeAmount);
24+
ethAmount = convertTokenAmountToEth(feeTokenAddress, feeAmount, event.address);
25+
shift.feeTokenAmount = shift.feeTokenAmount.plus(feeAmount);
26+
} else {
27+
ethAmount = feeAmount;
1628
}
17-
18-
shift.tokenAmount = shift.tokenAmount.plus(event.params._pnkAmount);
19-
const previousFeeAmount = shift.ethAmount;
20-
const newFeeAmount = shift.ethAmount.plus(event.params._feeAmount);
21-
shift.ethAmount = newFeeAmount;
29+
const previousEthAmount = shift.ethAmount;
30+
const newEthAmount = previousEthAmount.plus(ethAmount);
31+
shift.ethAmount = newEthAmount;
32+
resolveUserDispute(jurorAddress.toHexString(), previousEthAmount, newEthAmount, disputeID.toString());
33+
court.paidETH = court.paidETH.plus(ethAmount);
34+
updatePaidETH(ethAmount, event.block.timestamp);
35+
if (pnkAmount.gt(ZERO)) {
36+
court.paidPNK = court.paidPNK.plus(pnkAmount);
37+
updateRedistributedPNK(pnkAmount, event.block.timestamp);
38+
}
39+
shift.pnkAmount = shift.pnkAmount.plus(pnkAmount);
2240
shift.save();
23-
resolveUserDispute(jurorAddress, previousFeeAmount, newFeeAmount, disputeID);
41+
court.save();
2442
}
2543

26-
export function createTokenAndEthShiftFromEvent(event: TokenAndETHShiftEvent): void {
27-
const jurorAddress = event.params._account.toHexString();
28-
const disputeID = event.params._disputeID.toString();
29-
const shiftID = `${jurorAddress}-${disputeID}`;
30-
const shift = new TokenAndETHShift(shiftID);
31-
shift.juror = jurorAddress;
32-
shift.dispute = disputeID;
33-
shift.tokenAmount = event.params._pnkAmount;
34-
shift.ethAmount = event.params._feeAmount;
35-
shift.save();
44+
export function ensureTokenAndEthShift(
45+
jurorAddress: Address,
46+
disputeID: BigInt,
47+
roundIndex: BigInt,
48+
feeTokenAddress: Address
49+
): TokenAndETHShift {
50+
const shiftID = `${jurorAddress.toHexString()}-${disputeID.toString()}-${roundIndex.toString()}`;
51+
let shift = TokenAndETHShift.load(shiftID);
52+
if (!shift) {
53+
shift = new TokenAndETHShift(shiftID);
54+
if (feeTokenAddress !== Address.fromI32(0)) {
55+
shift.isNativeCurrency = false;
56+
shift.feeToken = feeTokenAddress.toHexString();
57+
} else {
58+
shift.isNativeCurrency = true;
59+
}
60+
shift.feeTokenAmount = ZERO;
61+
shift.ethAmount = ZERO;
62+
shift.juror = jurorAddress.toHexString();
63+
shift.dispute = disputeID.toString();
64+
shift.pnkAmount = ZERO;
65+
shift.save();
66+
}
67+
return shift;
3668
}

subgraph/subgraph.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ dataSources:
5454
handler: handleTokenAndETHShift
5555
- event: Ruling(indexed address,indexed uint256,uint256)
5656
handler: handleRuling
57+
- event: AcceptedFeeToken(indexed address,indexed bool)
58+
handler: handleAcceptedFeeToken
5759
file: ./src/KlerosCore.ts
5860
- kind: ethereum
5961
name: PolicyRegistry

web/package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,7 @@
2323
},
2424
"packageManager": "[email protected]",
2525
"scripts": {
26-
"clear": "rm -r .parcel-cache",
27-
"clean": "rm dist/bundle.js",
26+
"clear": "rm -fr ../.parcel-cache dist/bundle.js",
2827
"start": "parcel",
2928
"start-local": "REACT_APP_SUBGRAPH_ENDPOINT=http://localhost:8000/subgraphs/name/kleros/kleros-v2-core-local parcel",
3029
"build": "yarn generate && yarn parcel build",
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import React from "react";
2+
import styled, { css } from "styled-components";
3+
4+
const LinearGradientPath = styled.path<{ gradient: string }>`
5+
${({ gradient }) =>
6+
gradient &&
7+
css`
8+
stroke: url(#${gradient});
9+
`}
10+
`;
11+
12+
interface IGradientTokenIcons {
13+
icon: string;
14+
}
15+
16+
const GradientTokenIcons: React.FC<IGradientTokenIcons> = ({ icon }) => {
17+
return (
18+
<>
19+
{icon === "ETH" ? (
20+
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
21+
<LinearGradientPath
22+
gradient="eth"
23+
id="paint0_linear_14360_27088"
24+
d="M9.86602 28.0687L22.923 36.0836V47.1905L9.86602 28.0687ZM23.423 36.0836L36.4799 28.0687L23.423 47.1905V36.0836ZM23.423 16.428V0.930308L36.666 23.7911L23.423 16.428ZM36.8415 24.4607L23.423 32.703V17L36.8415 24.4607ZM22.923 0.929777V16.4279L9.67081 23.7913L22.923 0.929777ZM22.923 32.7032L9.49539 24.4607L22.923 16.9999V32.7032Z"
25+
/>
26+
<defs>
27+
<linearGradient id="eth" x1="23.173" y1="0" x2="23.173" y2="48" gradientUnits="userSpaceOnUse">
28+
<stop stopColor="#6CC5FF" />
29+
<stop offset="1" stopColor="#B45FFF" />
30+
</linearGradient>
31+
</defs>
32+
</svg>
33+
) : (
34+
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
35+
<LinearGradientPath
36+
gradient="pnk"
37+
fillRule="evenodd"
38+
clipRule="evenodd"
39+
d="M15.7151 6L35.6632 7.30096L43.9078 25.526L32.6361 42L12.2385 41.132L4 21.1862L15.7151 6ZM16.2222 7.03373L13.1105 22.2033L31.3917 13.6461L16.2222 7.03373ZM31.8965 14.3445L13.3445 23.0284L29.1334 34.8701L31.8965 14.3445ZM28.5319 35.4771L12.9497 23.7905V40.1518L28.5319 35.4771ZM12.1032 38.5872V23.2874L5.18188 21.8302L12.1032 38.5872ZM5.23158 20.9756L12.1974 22.4421L15.1303 8.14394L5.23158 20.9756ZM15.0532 40.4045L31.7195 41.1137L29.2373 36.1493L15.0532 40.4045ZM29.9956 35.773L32.4763 40.7345L41.6905 27.2676L29.9956 35.773ZM41.9695 23.295L35.3631 8.69144L32.9292 13.5593L41.9695 23.295ZM32.2205 13.0839L18.3024 7.01704L34.7186 8.08766L32.2205 13.0839ZM32.7193 14.5773L30.0082 34.7171L42.7892 25.4218L32.7193 14.5773Z"
40+
fill="url(#paint0_linear_14360_27090)"
41+
/>
42+
<defs>
43+
<linearGradient id="pnk" x1="23.9539" y1="6" x2="23.9539" y2="42" gradientUnits="userSpaceOnUse">
44+
<stop stopColor="#6CC5FF" />
45+
<stop offset="1" stopColor="#B45FFF" />
46+
</linearGradient>
47+
</defs>
48+
</svg>
49+
)}
50+
</>
51+
);
52+
};
53+
export default GradientTokenIcons;

web/src/context/Web3Provider.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ const { publicClient, webSocketPublicClient } = configureChains(chains, [
2222
]);
2323

2424
const wagmiConfig = createConfig({
25-
autoConnect: false,
25+
autoConnect: true,
2626
connectors: w3mConnectors({ projectId, version: 2, chains }),
2727
publicClient,
2828
webSocketPublicClient,

web/src/pages/Cases/CaseDetails/Overview.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,11 @@ const Overview: React.FC<IOverview> = ({ arbitrable, courtID, currentPeriodIndex
137137
</StyledA>
138138
)}
139139
{courtPolicy && (
140-
<StyledA href={`https://cloudflare-ipfs.com${courtPolicyURI}`} target="_blank" rel="noreferrer">
140+
<StyledA
141+
href={`https://cloudflare-ipfs.com${courtPolicyURI?.court?.policy ?? ""}`}
142+
target="_blank"
143+
rel="noreferrer"
144+
>
141145
<PolicyIcon />
142146
Court Policy
143147
</StyledA>

0 commit comments

Comments
 (0)