From bf021aa0b2712b22e226af6ff681e5c45cf5f571 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rn=20Andre=20Tangen=20=40gorillatron?= Date: Thu, 18 Jan 2024 14:08:26 +0100 Subject: [PATCH 1/4] Implement court exiting --- components/court/CourtExitButton.tsx | 141 ++++++++++++++++++ components/court/JurorsTable.tsx | 3 +- .../queries/court/useCourtParticipants.ts | 4 +- pages/court/index.tsx | 46 ++---- 4 files changed, 160 insertions(+), 34 deletions(-) create mode 100644 components/court/CourtExitButton.tsx diff --git a/components/court/CourtExitButton.tsx b/components/court/CourtExitButton.tsx new file mode 100644 index 000000000..dfff98bec --- /dev/null +++ b/components/court/CourtExitButton.tsx @@ -0,0 +1,141 @@ +import { Dialog } from "@headlessui/react"; +import { useQueryClient } from "@tanstack/react-query"; +import { isRpcSdk, timespanOf, ZTG } from "@zeitgeistpm/sdk"; +import { blockDate, dateBlock, toMs } from "@zeitgeistpm/utility/dist/time"; +import Modal from "components/ui/Modal"; +import TransactionButton from "components/ui/TransactionButton"; +import { BLOCK_TIME_SECONDS, DAY_SECONDS } from "lib/constants"; +import { useConnectedCourtParticipant } from "lib/hooks/queries/court/useConnectedCourtParticipant"; +import { courtParticipantsRootKey } from "lib/hooks/queries/court/useCourtParticipants"; +import { useChainConstants } from "lib/hooks/queries/useChainConstants"; +import { useExtrinsic } from "lib/hooks/useExtrinsic"; +import { useSdkv2 } from "lib/hooks/useSdkv2"; +import { useChainTime } from "lib/state/chaintime"; +import { useNotifications } from "lib/state/notifications"; +import { useWallet } from "lib/state/wallet"; +import moment from "moment"; +import { useMemo, useState } from "react"; + +const CourtExitButton = ({ className }: { className?: string }) => { + const [isOpen, setIsOpen] = useState(false); + const { data: constants } = useChainConstants(); + const [sdk, id] = useSdkv2(); + const notificationStore = useNotifications(); + const wallet = useWallet(); + const participant = useConnectedCourtParticipant(); + const queryClient = useQueryClient(); + const time = useChainTime(); + + const { + isLoading: isLeaveLoading, + send: leaveCourt, + fee, + } = useExtrinsic( + () => { + if (!isRpcSdk(sdk) || !wallet.realAddress) return; + return sdk.api.tx.court.exitCourt(wallet.realAddress); //todo: is this correct input? + }, + { + onSuccess: () => { + queryClient.invalidateQueries([id, courtParticipantsRootKey]); + notificationStore.pushNotification("Successfully exited court", { + type: "Success", + }); + }, + }, + ); + + // if (constants?.court.inflationPeriodBlocks) { + // constants.court.inflationPeriodBlocks = 70; + // } + + const cooldownTime = useMemo(() => { + if (time && participant && constants && participant?.prepareExitAt) { + const preparedExitAt = participant?.prepareExitAt; + const canExitAt = preparedExitAt + constants?.court.inflationPeriodBlocks; + + return { + total: toMs(time, { + start: 0, + end: constants?.court.inflationPeriodBlocks, + }), + left: toMs(time, { start: time?.block, end: canExitAt }), + }; + } + + return null; + }, [time, participant, constants]); + + const canExit = !Boolean(cooldownTime?.left && cooldownTime?.left > 0); + + const percentage = cooldownTime + ? 100 - (cooldownTime?.left / cooldownTime?.total) * 100 + : null; + + console.log(cooldownTime?.left, cooldownTime?.total); + return ( + <> + + setIsOpen(false)}> + +

Exit Court

+
+
+
Stake:
+
+ {participant?.stake.div(ZTG).toNumber()}{" "} + {constants?.tokenSymbol} +
+
+
+

+ By confirming exit you will leave the court, your stake will be + unlocked and moved back to your free balance. +

+
+
+ + Network Fee: {fee ? fee.amount.div(ZTG).toFixed(3) : 0}{" "} + {fee?.symbol} + +
+ leaveCourt()} + > + Confirm Exit + +
+
+
+ + ); +}; + +export default CourtExitButton; diff --git a/components/court/JurorsTable.tsx b/components/court/JurorsTable.tsx index 206d01840..82e6f382e 100644 --- a/components/court/JurorsTable.tsx +++ b/components/court/JurorsTable.tsx @@ -5,6 +5,7 @@ import DelegateButton from "./DelegateButton"; import { useCourtParticipants } from "lib/hooks/queries/court/useCourtParticipants"; import Decimal from "decimal.js"; import { ZTG } from "@zeitgeistpm/sdk"; +import { isNumber } from "lodash-es"; const columns: TableColumn[] = [ { @@ -68,7 +69,7 @@ const JurorsTable = () => { ), personalStake: juror.stake.div(ZTG).toNumber(), totalStake: juror.stake.plus(delegatorStake).div(ZTG).toNumber(), - status: juror.prepareExit ? "Exiting" : "Active", + status: isNumber(juror.prepareExitAt) ? "Exiting" : "Active", delegators: delegators.length, button: , }; diff --git a/lib/hooks/queries/court/useCourtParticipants.ts b/lib/hooks/queries/court/useCourtParticipants.ts index 62bf1f701..8ce51ead1 100644 --- a/lib/hooks/queries/court/useCourtParticipants.ts +++ b/lib/hooks/queries/court/useCourtParticipants.ts @@ -26,7 +26,9 @@ export const useCourtParticipants = () => { return { address: (address.toHuman() as [string])[0], stake: new Decimal(unwrappedDetails?.stake.toString() ?? 0), - prepareExit: unwrappedDetails?.prepareExitAt.isSome, + prepareExitAt: unwrappedDetails?.prepareExitAt + .unwrapOr(null) + ?.toNumber(), type: unwrappedDetails?.delegations.isSome ? ("Delegator" as const) : ("Juror" as const), diff --git a/pages/court/index.tsx b/pages/court/index.tsx index 7a83deade..a8258d289 100644 --- a/pages/court/index.tsx +++ b/pages/court/index.tsx @@ -1,17 +1,15 @@ import { Disclosure } from "@headlessui/react"; import { useQueryClient } from "@tanstack/react-query"; -import { ZTG, isRpcSdk } from "@zeitgeistpm/sdk"; +import { ZTG } from "@zeitgeistpm/sdk"; import { CourtCasesTable } from "components/court/CourtCasesTable"; +import CourtExitButton from "components/court/CourtExitButton"; +import CourtUnstakeButton from "components/court/CourtUnstakeButton"; import JoinCourtAsJurorButton from "components/court/JoinCourtAsJurorButton"; import ManageDelegationButton from "components/court/ManageDelegationButton"; -import CourtUnstakeButton from "components/court/CourtUnstakeButton"; import InfoPopover from "components/ui/InfoPopover"; import { useConnectedCourtParticipant } from "lib/hooks/queries/court/useConnectedCourtParticipant"; import { useCourtCases } from "lib/hooks/queries/court/useCourtCases"; -import { - courtParticipantsRootKey, - useCourtParticipants, -} from "lib/hooks/queries/court/useCourtParticipants"; +import { useCourtParticipants } from "lib/hooks/queries/court/useCourtParticipants"; import { useCourtStakeSharePercentage } from "lib/hooks/queries/court/useCourtStakeSharePercentage"; import { useCourtTotalStakedAmount } from "lib/hooks/queries/court/useCourtTotalStakedAmount"; import { @@ -20,11 +18,11 @@ import { } from "lib/hooks/queries/court/useCourtYearlyInflation"; import { useChainConstants } from "lib/hooks/queries/useChainConstants"; import { useZtgPrice } from "lib/hooks/queries/useZtgPrice"; -import { useExtrinsic } from "lib/hooks/useExtrinsic"; import { useSdkv2 } from "lib/hooks/useSdkv2"; import { useNotifications } from "lib/state/notifications"; import { useWallet } from "lib/state/wallet"; import { formatNumberLocalized } from "lib/util"; +import { isNumber } from "lodash-es"; import { NextPage } from "next"; import Image from "next/image"; import Link from "next/link"; @@ -55,31 +53,10 @@ const CourtPage: NextPage = ({ } const { data: constants } = useChainConstants(); - const [sdk, id] = useSdkv2(); - const notificationStore = useNotifications(); - const wallet = useWallet(); - const queryClient = useQueryClient(); - const connectedParticipant = useConnectedCourtParticipant(); const { data: ztgPrice } = useZtgPrice(); - const stakeShare = useCourtStakeSharePercentage(); - const { isLoading: isLeaveLoading, send: leaveCourt } = useExtrinsic( - () => { - if (!isRpcSdk(sdk) || !wallet.realAddress) return; - return sdk.api.tx.court.exitCourt(wallet.realAddress); //todo: is this correct input? - }, - { - onSuccess: () => { - queryClient.invalidateQueries([id, courtParticipantsRootKey]); - notificationStore.pushNotification("Successfully exited court", { - type: "Success", - }); - }, - }, - ); - return (
@@ -175,12 +152,17 @@ const CourtPage: NextPage = ({
- - + + + + {connectedParticipant && + !isNumber(connectedParticipant.prepareExitAt) && ( + + )} {connectedParticipant && - !connectedParticipant?.prepareExit && ( - + isNumber(connectedParticipant.prepareExitAt) && ( + )}
From 39a98e3550c702e5b566875a57024bc4a11232c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rn=20Andre=20Tangen=20=40gorillatron?= Date: Thu, 18 Jan 2024 14:09:52 +0100 Subject: [PATCH 2/4] Update CourtExitButton.tsx --- components/court/CourtExitButton.tsx | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/components/court/CourtExitButton.tsx b/components/court/CourtExitButton.tsx index dfff98bec..6c5d86aad 100644 --- a/components/court/CourtExitButton.tsx +++ b/components/court/CourtExitButton.tsx @@ -1,10 +1,9 @@ import { Dialog } from "@headlessui/react"; import { useQueryClient } from "@tanstack/react-query"; -import { isRpcSdk, timespanOf, ZTG } from "@zeitgeistpm/sdk"; -import { blockDate, dateBlock, toMs } from "@zeitgeistpm/utility/dist/time"; +import { isRpcSdk, ZTG } from "@zeitgeistpm/sdk"; +import { toMs } from "@zeitgeistpm/utility/dist/time"; import Modal from "components/ui/Modal"; import TransactionButton from "components/ui/TransactionButton"; -import { BLOCK_TIME_SECONDS, DAY_SECONDS } from "lib/constants"; import { useConnectedCourtParticipant } from "lib/hooks/queries/court/useConnectedCourtParticipant"; import { courtParticipantsRootKey } from "lib/hooks/queries/court/useCourtParticipants"; import { useChainConstants } from "lib/hooks/queries/useChainConstants"; @@ -33,7 +32,7 @@ const CourtExitButton = ({ className }: { className?: string }) => { } = useExtrinsic( () => { if (!isRpcSdk(sdk) || !wallet.realAddress) return; - return sdk.api.tx.court.exitCourt(wallet.realAddress); //todo: is this correct input? + return sdk.api.tx.court.exitCourt(wallet.realAddress); }, { onSuccess: () => { @@ -45,10 +44,6 @@ const CourtExitButton = ({ className }: { className?: string }) => { }, ); - // if (constants?.court.inflationPeriodBlocks) { - // constants.court.inflationPeriodBlocks = 70; - // } - const cooldownTime = useMemo(() => { if (time && participant && constants && participant?.prepareExitAt) { const preparedExitAt = participant?.prepareExitAt; From f80b9c9849d5afaae2cd4e0d9236fd7dde18c85f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rn=20Andre=20Tangen=20=40gorillatron?= Date: Thu, 18 Jan 2024 14:10:12 +0100 Subject: [PATCH 3/4] Update CourtExitButton.tsx --- components/court/CourtExitButton.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/components/court/CourtExitButton.tsx b/components/court/CourtExitButton.tsx index 6c5d86aad..186fba8d9 100644 --- a/components/court/CourtExitButton.tsx +++ b/components/court/CourtExitButton.tsx @@ -67,7 +67,6 @@ const CourtExitButton = ({ className }: { className?: string }) => { ? 100 - (cooldownTime?.left / cooldownTime?.total) * 100 : null; - console.log(cooldownTime?.left, cooldownTime?.total); return ( <>