Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/devtools ruler functionality #1694

Merged
merged 17 commits into from
Oct 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
bf8e8b8
feat(web-devtools): ruler-functionality
Harman-singh-waraich Sep 25, 2024
ae1779f
chore(web-devtools): update-yarn-lockfile
Harman-singh-waraich Sep 25, 2024
bb2dbe2
refactor(web-devtools): coderabbit-fixes
Harman-singh-waraich Sep 25, 2024
f360928
fix(web-devtools): wallet-connect-env-name
Harman-singh-waraich Sep 25, 2024
baa186e
refactor(web-devtools): remove-arbitrator-ruler-check
Harman-singh-waraich Sep 25, 2024
4e0b208
feat(web-devtools): add-connect-wallet-button
Harman-singh-waraich Sep 25, 2024
28e2411
chore(web-devtools): configure-typing
Harman-singh-waraich Sep 26, 2024
a5b995a
feat(web-devtools): inputable-dropdown-for-arbitrables-with-storage-s…
Harman-singh-waraich Sep 26, 2024
db886f0
feat(web-devtools): display-copiable-ruler-address
Harman-singh-waraich Sep 27, 2024
d0356d6
fix(web-devtools): remove-incorrect-default-checked-logic-in-radio-bu…
Harman-singh-waraich Sep 27, 2024
6f8cdc7
fix(web-devtools): fix-ruling-modes-enum
Harman-singh-waraich Sep 27, 2024
98eb691
refactor(web-devtools): hide-automatic-preset-options-while-it-is-not…
Harman-singh-waraich Oct 2, 2024
ffe48c5
refactor(web-devtools): single-connect-button-at-top-level
Harman-singh-waraich Oct 2, 2024
9ce49a2
refactor(web-devtools): replace-conflicting-ruling-settings-update-wi…
Harman-singh-waraich Oct 2, 2024
2c62886
refactor(web-devtools): update-labeled-input-style
Harman-singh-waraich Oct 4, 2024
62dac29
feat(web-devtools): tooltip-for-different-sections
Harman-singh-waraich Oct 4, 2024
a3146ab
fix(web-devtools): fix-typo
Harman-singh-waraich Oct 7, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion web-devtools/.env.local.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
export NEXT_PUBLIC_ALCHEMY_API_KEY=
export NEXT_PUBLIC_DEPLOYMENT=devnet
export NEXT_PUBLIC_CORE_SUBGRAPH=https://api.studio.thegraph.com/query/61738/kleros-v2-core-devnet/version/latest
export NEXT_PUBLIC_DRT_ARBSEPOLIA_SUBGRAPH=https://api.studio.thegraph.com/query/61738/kleros-v2-drt-arbisep-devnet/version/latest
export NEXT_PUBLIC_DRT_ARBSEPOLIA_SUBGRAPH=https://api.studio.thegraph.com/query/61738/kleros-v2-drt-arbisep-devnet/version/latest
export NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID=
11 changes: 10 additions & 1 deletion web-devtools/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,28 @@
"@types/node": "^20",
"@types/react": "18.2.0",
"@types/react-dom": "^18.2.18",
"@typescript-eslint/eslint-plugin": "^5.62.0",
"@typescript-eslint/parser": "^5.62.0",
"@typescript-eslint/utils": "^5.62.0",
"@wagmi/cli": "^2.0.3",
"eslint": "^8.56.0",
"eslint-config-next": "^14.2.5",
"eslint-config-prettier": "^8.10.0",
"eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0",
"ts-node": "^10.9.2",
"typescript": "^5.5.3"
},
"dependencies": {
"@kleros/kleros-sdk": "workspace:^",
"@kleros/ui-components-library": "^2.10.0",
"@kleros/ui-components-library": "^2.15.0",
"graphql": "^16.9.0",
"next": "14.2.4",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-markdown": "^8.0.7",
"react-toastify": "^10.0.5",
"typewriter-effect": "^2.21.0",
"vanilla-jsoneditor": "^0.21.4",
"viem": "^2.1.0",
Expand Down
23 changes: 18 additions & 5 deletions web-devtools/src/app/(main)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,35 @@
import React from "react";
import styled from "styled-components";

import "react-toastify/dist/ReactToastify.css";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ToastContainer } from "react-toastify";

import GraphqlBatcherProvider from "context/GraphqlBatcher";
import Web3Provider from "context/Web3Provider";

const Main = styled.main`
min-height: calc(100vh - 130px);
`;
const queryClient = new QueryClient();

const StyledToastContainer = styled(ToastContainer)`
padding: 16px;
padding-top: 70px;
`;

const Layout = ({ children }: Readonly<{ children: React.ReactNode }>) => {
return (
<QueryClientProvider client={queryClient}>
<GraphqlBatcherProvider>
<Main>{children}</Main>
</GraphqlBatcherProvider>
</QueryClientProvider>
<Web3Provider>
<QueryClientProvider client={queryClient}>
<GraphqlBatcherProvider>
<Main>
<StyledToastContainer />
{children}
</Main>
</GraphqlBatcherProvider>
</QueryClientProvider>
</Web3Provider>
);
};

Expand Down
65 changes: 60 additions & 5 deletions web-devtools/src/app/(main)/ruler/ChangeDeveloper.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
import React from "react";
import React, { useCallback, useMemo, useState } from "react";
import styled from "styled-components";

import { Address, isAddress } from "viem";
import { useAccount, usePublicClient } from "wagmi";

import { Button } from "@kleros/ui-components-library";

import { useRulerContext } from "context/RulerContext";
import { useSimulateKlerosCoreRulerChangeRuler, useWriteKlerosCoreRulerChangeRuler } from "hooks/contracts/generated";
import { isUndefined } from "utils/isUndefined";
import { wrapWithToast } from "utils/wrapWithToast";

import LabeledInput from "components/LabeledInput";

import Header from "./Header";
import { DEFAULT_CHAIN } from "consts/chains";

const Container = styled.div`
width: 100%;
Expand All @@ -25,14 +34,60 @@ const StyledLabel = styled.label`
`;

const ChangeDeveloper: React.FC = () => {
const { isConnected, chainId } = useAccount();
const { arbitrable, currentDeveloper, refetchData } = useRulerContext();
const [newDeveloper, setNewDeveloper] = useState("");
const [isChanging, setIsChanging] = useState(false);
const publicClient = usePublicClient();

const isValid = useMemo(() => newDeveloper === "" || isAddress(newDeveloper), [newDeveloper]);

const {
data: changeRulerConfig,
isLoading,
isError,
} = useSimulateKlerosCoreRulerChangeRuler({
query: {
enabled: !isUndefined(arbitrable) && !isUndefined(newDeveloper) && isAddress(newDeveloper),
},
args: [(arbitrable ?? "") as Address, newDeveloper as Address],
});

const { writeContractAsync: changeRuler } = useWriteKlerosCoreRulerChangeRuler();

const handleClick = useCallback(() => {
if (!publicClient || !changeRulerConfig) return;
setIsChanging(true);
wrapWithToast(async () => changeRuler(changeRulerConfig.request), publicClient)
.then(() => refetchData())
.finally(() => setIsChanging(false));
}, [publicClient, changeRulerConfig, changeRuler, refetchData]);

const isDisabled = useMemo(
() =>
!isConnected ||
chainId !== DEFAULT_CHAIN ||
!changeRulerConfig ||
isError ||
isLoading ||
isChanging ||
isUndefined(arbitrable) ||
!isValid,
[changeRulerConfig, isError, isLoading, isChanging, arbitrable, isValid, isConnected, chainId]
);
return (
<Container>
<Header text="Developer" />
<Header text="Developer" tooltipMsg="Address of the current ruler of the selected arbitrable" />
<InputContainer>
<StyledLabel>Current Developer : 0xbe8d95497E53aB41d5A45CC8def90d0e59b49f99</StyledLabel>
<LabeledInput label="New Developer" />
<StyledLabel>Current Developer : {currentDeveloper ?? "None"}</StyledLabel>
<LabeledInput
label="New Developer"
onChange={(e) => setNewDeveloper(e.target.value)}
message={isValid ? "" : "Invalid Address"}
variant={isValid ? "" : "error"}
/>
</InputContainer>
<Button text="Update" />
<Button text="Update" onClick={handleClick} isLoading={isLoading || isChanging} disabled={isDisabled} />
</Container>
);
};
Expand Down
18 changes: 16 additions & 2 deletions web-devtools/src/app/(main)/ruler/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,25 @@
import React from "react";
import styled from "styled-components";
import WithHelpTooltip from "components/WithHelpTooltip";

const Container = styled.h2`
const Container = styled.div`
width: 100%;
display: flex;
align-items: center;
border-bottom: 1px solid ${({ theme }) => theme.klerosUIComponentsStroke};
padding: 8px 0px;
`;

const Header: React.FC<{ text: string }> = ({ text }) => <Container>{text}</Container>;
const Title = styled.h2`
margin: 0;
`;

const Header: React.FC<{ text: string; tooltipMsg: string }> = ({ text, tooltipMsg }) => (
<Container>
<WithHelpTooltip tooltipMsg={tooltipMsg} place="right">
<Title>{text}</Title>
</WithHelpTooltip>
</Container>
);

export default Header;
98 changes: 89 additions & 9 deletions web-devtools/src/app/(main)/ruler/ManualRuling.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,26 @@
import React, { useState } from "react";
"use client";
import React, { useCallback, useMemo, useState } from "react";
import styled from "styled-components";

import { RULING_MODE } from "consts";
import { useAccount, usePublicClient } from "wagmi";

import { Button } from "@kleros/ui-components-library";

import { useRulerContext } from "context/RulerContext";
import {
useSimulateKlerosCoreRulerChangeRulingModeToManual,
useSimulateKlerosCoreRulerExecuteRuling,
useWriteKlerosCoreRulerChangeRulingModeToManual,
useWriteKlerosCoreRulerExecuteRuling,
} from "hooks/contracts/generated";
import { isUndefined } from "utils/isUndefined";
import { wrapWithToast } from "utils/wrapWithToast";

import LabeledInput from "components/LabeledInput";

import Header from "./Header";
import { DEFAULT_CHAIN } from "consts/chains";

const Container = styled.div`
width: 100%;
Expand All @@ -22,14 +37,75 @@ const SelectContainer = styled.div`
`;

const ManualRuling: React.FC = () => {
const [tie, setTie] = useState<boolean>(false);
const [overriden, setOverriden] = useState<boolean>(false);
const { isConnected, chainId } = useAccount();
const { arbitrable, arbitrableSettings } = useRulerContext();
const [isSending, setIsSending] = useState<boolean>(false);
const [tie, setTie] = useState(arbitrableSettings?.tied ?? false);
const [overridden, setOverridden] = useState(arbitrableSettings?.overridden ?? false);
const [ruling, setRuling] = useState(arbitrableSettings?.ruling);
const [disputeId, setDisputeId] = useState<number>();
const [ruling, setRuling] = useState<number>();

const publicClient = usePublicClient();

const { data: manualModeConfig } = useSimulateKlerosCoreRulerChangeRulingModeToManual({
query: {
enabled: arbitrableSettings?.rulingMode !== RULING_MODE.Manual && !isUndefined(arbitrable),
},
args: [arbitrable as `0x${string}`],
});
const { writeContractAsync: changeToManualMode } = useWriteKlerosCoreRulerChangeRulingModeToManual();

const isDisabled = useMemo(() => {
return (
!isConnected ||
chainId !== DEFAULT_CHAIN ||
isUndefined(disputeId) ||
isUndefined(ruling) ||
isUndefined(arbitrable)
);
}, [disputeId, ruling, arbitrable, isConnected, chainId]);

const {
data: executeConfig,
isLoading: isLoadingExecuteConfig,
isError,
} = useSimulateKlerosCoreRulerExecuteRuling({
query: {
enabled: arbitrableSettings?.rulingMode === RULING_MODE.Manual && !isUndefined(arbitrable) && !isDisabled,
},
args: [BigInt(disputeId ?? 0), BigInt(ruling ?? 0), tie, overridden],
});

const { writeContractAsync: executeRuling } = useWriteKlerosCoreRulerExecuteRuling();

const handleRuling = useCallback(async () => {
if (!publicClient) return;
if (arbitrableSettings?.rulingMode !== RULING_MODE.Manual) {
if (!manualModeConfig) return;
setIsSending(true);

wrapWithToast(async () => await changeToManualMode(manualModeConfig.request), publicClient)
.then(async (res) => {
if (res.status && executeConfig) {
wrapWithToast(async () => await executeRuling(executeConfig.request), publicClient);
}
})
.finally(() => setIsSending(false));
} else if (executeConfig) {
setIsSending(true);

wrapWithToast(async () => await executeRuling(executeConfig.request), publicClient).finally(() =>
setIsSending(false)
);
}
}, [publicClient, executeConfig, manualModeConfig, arbitrableSettings, changeToManualMode, executeRuling]);

return (
<Container>
<Header text="Manual Ruling" />
<Header
text="Manual Ruling"
tooltipMsg="Provide Manual ruling for the arbitrator. This operation will change the ruling mode to Manual, if the ruling mode is not Manual"
/>
<SelectContainer>
<LabeledInput
label="Dispute ID"
Expand All @@ -43,12 +119,16 @@ const ManualRuling: React.FC = () => {
<LabeledInput
label="Overidden"
inputType="checkbox"
checked={overriden}
onChange={() => setOverriden((prev) => !prev)}
checked={overridden}
onChange={() => setOverridden((prev) => !prev)}
/>
</SelectContainer>

<Button text="Rule" />
<Button
text="Rule"
onClick={handleRuling}
isLoading={isLoadingExecuteConfig || isSending}
disabled={isDisabled || isError || isSending || isLoadingExecuteConfig}
/>
</Container>
);
};
Expand Down
Loading
Loading