From 67b32978fae3e551977b5111ea07aeed468ebb52 Mon Sep 17 00:00:00 2001 From: vkulinich Date: Wed, 25 Sep 2024 16:37:54 +0200 Subject: [PATCH 01/10] Implement Open Gov --- src/api/democracy.ts | 91 +++++- src/api/staking.ts | 79 +----- src/assets/icons/Calendar.svg | 3 + src/assets/icons/ChevronFull.svg | 3 + src/assets/icons/ChevronRightSmall.svg | 3 - src/assets/icons/StakingVote.svg | 9 + .../Dropdown/DropdownRebranded.styled.ts | 114 ++++++++ src/components/Dropdown/DropdownRebranded.tsx | 71 +++++ src/components/ReferendumCard/NoReferenda.tsx | 42 +++ src/components/ReferendumCard/Referenda.tsx | 263 ++++++++++++++++++ .../ReferendumCard/Referenda.utils.ts | 155 +++++++++++ .../ReferendumCard/ReferendaSkeleton.tsx | 64 +++++ .../ReferendumCard/ReferendumCard.styled.ts | 75 +++++ .../Toast/sidebar/group/ToastSidebarGroup.tsx | 6 +- .../referendums/ToastSidebarReferendums.tsx | 62 +++-- src/i18n/locales/en/translations.json | 11 +- src/sections/staking/StakingPage.utils.ts | 88 +----- .../sections/dashboard/StakingDashboard.tsx | 6 +- .../components/Referenda/Referenda.tsx | 75 ----- .../components/Referenda/Referendas.tsx | 187 +++++++++++++ src/utils/formatting.ts | 4 + src/utils/opengov.ts | 82 ++++++ src/utils/queryKeys.ts | 10 +- 23 files changed, 1227 insertions(+), 276 deletions(-) create mode 100644 src/assets/icons/Calendar.svg create mode 100644 src/assets/icons/ChevronFull.svg delete mode 100644 src/assets/icons/ChevronRightSmall.svg create mode 100644 src/assets/icons/StakingVote.svg create mode 100644 src/components/Dropdown/DropdownRebranded.styled.ts create mode 100644 src/components/Dropdown/DropdownRebranded.tsx create mode 100644 src/components/ReferendumCard/NoReferenda.tsx create mode 100644 src/components/ReferendumCard/Referenda.tsx create mode 100644 src/components/ReferendumCard/Referenda.utils.ts create mode 100644 src/components/ReferendumCard/ReferendaSkeleton.tsx delete mode 100644 src/sections/staking/sections/dashboard/components/Referenda/Referenda.tsx create mode 100644 src/sections/staking/sections/dashboard/components/Referenda/Referendas.tsx create mode 100644 src/utils/opengov.ts diff --git a/src/api/democracy.ts b/src/api/democracy.ts index 8d00e3a7e..e5cc82dec 100644 --- a/src/api/democracy.ts +++ b/src/api/democracy.ts @@ -4,11 +4,17 @@ import { QUERY_KEYS } from "utils/queryKeys" import { useAccount } from "sections/web3-connect/Web3Connect.utils" import { useRpcProvider } from "providers/rpcProvider" import { undefinedNoop } from "utils/helpers" -import { PalletDemocracyVoteAccountVote } from "@polkadot/types/lookup" -import BN from "bignumber.js" +import { + PalletDemocracyVoteAccountVote, + PalletReferendaReferendumStatus, + PalletReferendaCurve, +} from "@polkadot/types/lookup" +import BN, { BigNumber } from "bignumber.js" import { BN_0 } from "utils/constants" +import { humanizeUnderscoredString } from "utils/formatting" +import { SubstrateApis } from "@galacticcouncil/xcm-core" -const REFERENDUM_DATA_URL = import.meta.env.VITE_REFERENDUM_DATA_URL as string +const REFERENDUM_DATA_URL = "https://basilisk.subsquare.io/api/gov2/referendums" //import.meta.env.VITE_REFERENDUM_DATA_URL as string const CONVICTIONS_BLOCKS: { [key: string]: number } = { none: 0, @@ -65,6 +71,36 @@ export const useReferendumInfo = (referendumIndex: string) => { ) } +export const useOpenGovReferendas = () => { + const { api, isLoaded } = useRpcProvider() + + return useQuery(QUERY_KEYS.openGovReferendas, getOpenGovRegerendas(api), { + enabled: isLoaded, + }) +} + +const getOpenGovRegerendas = (api: ApiPromise) => async () => { + const apiPool = SubstrateApis.getInstance() + const api = await apiPool.api("wss://basilisk-rpc.dwellir.com") + + const newReferendumsRaw = + await api.query.referenda.referendumInfoFor.entries() + + // get only ongoing referenas so far + return newReferendumsRaw.reduce< + Array<{ id: string; referendum: PalletReferendaReferendumStatus }> + >((acc, [key, dataRaw]) => { + const id = key.args[0].toString() + const data = dataRaw.unwrap() + + if (!data.isNone && data.isOngoing) { + acc.push({ id, referendum: data.asOngoing }) + } + + return acc + }, []) +} + export const getReferendums = (api: ApiPromise, accountId?: string) => async () => { const [referendumRaw, votesRaw] = await Promise.all([ @@ -228,3 +264,52 @@ export const getAccountUnlockedVotes = return unlockedVotes } + +export const useReferendaTracks = () => { + const { api, isLoaded } = useRpcProvider() + + return useQuery( + QUERY_KEYS.referendaTracks, + async () => { + const apiPool = SubstrateApis.getInstance() + const api = await apiPool.api("wss://basilisk-rpc.dwellir.com") + const tracks = await api.consts.referenda.tracks + + const data: Map = new Map( + tracks.map(([key, dataRaw]) => [ + key.toString(), + { + name: dataRaw.name.toString(), + nameHuman: humanizeUnderscoredString(dataRaw.name.toString()), + maxDeciding: dataRaw.maxDeciding.toBigNumber(), + decisionDeposit: dataRaw.decisionDeposit.toBigNumber(), + preparePeriod: dataRaw.preparePeriod.toBigNumber(), + decisionPeriod: dataRaw.decisionPeriod.toBigNumber(), + confirmPeriod: dataRaw.confirmPeriod.toBigNumber(), + minEnactmentPeriod: dataRaw.minEnactmentPeriod.toBigNumber(), + minApproval: dataRaw.minApproval, + minSupport: dataRaw.minSupport, + }, + ]), + ) + + return data + }, + { + enabled: isLoaded, + }, + ) +} + +export type TReferenda = { + name: string + nameHuman: string + maxDeciding: BigNumber + decisionDeposit: BigNumber + preparePeriod: BigNumber + decisionPeriod: BigNumber + confirmPeriod: BigNumber + minEnactmentPeriod: BigNumber + minApproval: PalletReferendaCurve + minSupport: PalletReferendaCurve +} diff --git a/src/api/staking.ts b/src/api/staking.ts index b10293aa2..c67058ea5 100644 --- a/src/api/staking.ts +++ b/src/api/staking.ts @@ -7,7 +7,6 @@ import request, { gql } from "graphql-request" import { useActiveProvider } from "./provider" import { useRpcProvider } from "providers/rpcProvider" import { useAccount } from "sections/web3-connect/Web3Connect.utils" -import { undefinedNoop } from "utils/helpers" interface ISubscanData { code: number @@ -46,20 +45,22 @@ export type TStakingPosition = Awaited< ReturnType> > -export const useCirculatingSupply = () => { +export const useHDXSupplyFromSubscan = () => { return useQuery( - QUERY_KEYS.circulatingSupply, + QUERY_KEYS.hdxSupply, async () => { - const res = await getCirculatingSupply()() + const res = await getHDXSupplyFromSubscan()() - return res.data.detail["HDX"].available_balance + const HDXData = res.data.detail["BSX"] + + return HDXData }, { retry: 0 }, ) } -const getCirculatingSupply = () => async () => { - const res = await fetch("https://hydration.api.subscan.io/api/scan/token") +const getHDXSupplyFromSubscan = () => async () => { + const res = await fetch("https://basilisk.api.subscan.io/api/scan/token") const data: Promise = res.json() @@ -202,29 +203,6 @@ type TStakingInitialized = StakeEventBase & { name: "Staking.StakingInitialized" } -type TPositionBalance = StakeEventBase & - ( - | { - name: "Staking.PositionCreated" - args: { - positionId: string - stake: string - who: string - } - } - | { - name: "Staking.StakeAdded" - args: { - lockedRewards: string - positionId: string - slashedPoints: string - stake: string - totalStake: string - who: string - } - } - ) - export type TAccumulatedRpsUpdated = StakeEventBase & { name: "Staking.AccumulatedRpsUpdated" args: { @@ -251,18 +229,6 @@ export const useStakingEvents = () => { }) } -export const useStakingPositionBalances = (positionId?: string) => { - const { indexerUrl } = useActiveProvider() - - return useQuery( - QUERY_KEYS.stakingPositionBalances(positionId), - positionId - ? getStakingPositionBalances(indexerUrl, positionId) - : undefinedNoop, - { enabled: !!positionId }, - ) -} - const getAccumulatedRpsUpdatedEvents = (indexerUrl: string) => async () => { return { ...(await request<{ @@ -307,35 +273,6 @@ const getStakingInitializedEvents = (indexerUrl: string) => async () => { } } -const getStakingPositionBalances = - (indexerUrl: string, positionId: string) => async () => { - return { - ...(await request<{ - events: Array - }>( - indexerUrl, - gql` - query StakingPositionBalances($positionId: String!) { - events( - where: { - name_contains: "Staking" - args_jsonContains: { positionId: $positionId } - } - orderBy: [block_height_ASC] - ) { - name - block { - height - } - args - } - } - `, - { positionId }, - )), - } - } - export const useProcessedVotesIds = () => { const { account } = useAccount() const { api } = useRpcProvider() diff --git a/src/assets/icons/Calendar.svg b/src/assets/icons/Calendar.svg new file mode 100644 index 000000000..2059dd01e --- /dev/null +++ b/src/assets/icons/Calendar.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/assets/icons/ChevronFull.svg b/src/assets/icons/ChevronFull.svg new file mode 100644 index 000000000..3cf878f65 --- /dev/null +++ b/src/assets/icons/ChevronFull.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/ChevronRightSmall.svg b/src/assets/icons/ChevronRightSmall.svg deleted file mode 100644 index 250dad790..000000000 --- a/src/assets/icons/ChevronRightSmall.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/assets/icons/StakingVote.svg b/src/assets/icons/StakingVote.svg new file mode 100644 index 000000000..be1ac6e31 --- /dev/null +++ b/src/assets/icons/StakingVote.svg @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/components/Dropdown/DropdownRebranded.styled.ts b/src/components/Dropdown/DropdownRebranded.styled.ts new file mode 100644 index 000000000..06ed9e43d --- /dev/null +++ b/src/components/Dropdown/DropdownRebranded.styled.ts @@ -0,0 +1,114 @@ +import { css, keyframes } from "@emotion/react" +import styled from "@emotion/styled" +import * as DropdownMenu from "@radix-ui/react-dropdown-menu" +import { theme } from "theme" + +export const fadeInKeyframes = keyframes` + 0% { + opacity: 0; + transform: scale(0.96); + } + + 100% { + opacity: 1; + transform: scale(1); + } +` +export const SItem = styled(DropdownMenu.Item)` + color: rgba(${theme.rgbColors.white}, 0.5); + font-size: 14px; + line-height: 26px; + + padding: 0 8px; + + font-weight: 500; + + display: flex; + align-items: center; + gap: 10px; + + border-radius: 8px; + + transition: all ${theme.transitions.default}; + + cursor: pointer; + + &:focus-visible, + &:hover { + outline: none; + color: ${theme.colors.basic100}; + background: rgba(${theme.rgbColors.white}, 0.06); + } + + svg { + color: ${theme.colors.pink500}; + } +` +export const SContent = styled(DropdownMenu.Content)` + display: flex; + flex-direction: column; + gap: 4px; + + background: #0d1525; + + border-radius: 12px; + + animation: 150ms cubic-bezier(0.16, 1, 0.3, 1) ${fadeInKeyframes}; + box-shadow: 0px 40px 70px 0px rgba(0, 0, 0, 0.8); + + padding: 10px; + + overflow-y: scroll; + max-height: 400px; + + z-index: ${theme.zIndices.toast}; +` +export const STrigger = styled(DropdownMenu.Trigger)` + all: unset; + + padding: 8px 14px; + + border-radius: 32px; + + min-width: 12px; + min-height: 12px; + + background: #0d1525; + color: ${theme.colors.brightBlue300}; + + transition: background ${theme.transitions.default}; + + border: 1px solid rgba(124, 127, 138, 0.2); + + display: flex; + align-items: center; + justify-content: center; + + cursor: pointer; + + overflow: hidden; + position: relative; + + &:hover { + opacity: 0.7; + } + + &[data-state="open"] { + & > div > span { + transition: transform ${theme.transitions.default}; + transform: rotate(180deg); + } + } + + ${({ disabled }) => + disabled && + css` + background: rgba(${theme.rgbColors.basic100}, 0.06); + color: ${theme.colors.darkBlue300}; + + border: 1px solid ${theme.colors.darkBlue300}; + + pointer-events: none; + cursor: not-allowed; + `} +` diff --git a/src/components/Dropdown/DropdownRebranded.tsx b/src/components/Dropdown/DropdownRebranded.tsx new file mode 100644 index 000000000..db63beb9a --- /dev/null +++ b/src/components/Dropdown/DropdownRebranded.tsx @@ -0,0 +1,71 @@ +import * as DropdownMenu from "@radix-ui/react-dropdown-menu" + +import React, { ReactNode } from "react" +import { SContent, SItem, STrigger } from "./DropdownRebranded.styled" +import { Text } from "components/Typography/Text/Text" +import Chevron from "assets/icons/ChevronFull.svg?react" +import { Icon } from "components/Icon/Icon" + +export type TDropdownItem = { + key: string + icon?: ReactNode + label: ReactNode + onSelect?: () => void + disabled?: boolean +} + +export type DropdownProps = { + items: Array + children: ReactNode + onSelect: (key: TDropdownItem) => void + asChild?: boolean + align?: "start" | "center" | "end" +} + +export const Dropdown: React.FC = ({ + items, + children, + onSelect, + asChild, + align, +}) => { + return ( + + {asChild ? ( + {children} + ) : ( + {children} + )} + + + {items.map((i) => ( + onSelect(i)}> + {i.icon} + {i.label} + + ))} + + + + ) +} + +export const DropdownTriggerContent = ({ + title, + value, +}: { + title: string + value?: string +}) => { + return ( +
+ + {title}: + + + {value} + + } sx={{ color: "basic400" }} /> +
+ ) +} diff --git a/src/components/ReferendumCard/NoReferenda.tsx b/src/components/ReferendumCard/NoReferenda.tsx new file mode 100644 index 000000000..838299007 --- /dev/null +++ b/src/components/ReferendumCard/NoReferenda.tsx @@ -0,0 +1,42 @@ +import { Text } from "components/Typography/Text/Text" +import { SHeader, SOpenGovContainer } from "./ReferendumCard.styled" +import { Separator } from "components/Separator/Separator" +import Calendar from "assets/icons/Calendar.svg?react" +import { Icon } from "components/Icon/Icon" +import { useTranslation } from "react-i18next" + +export const NoReferenda = () => { + const { t } = useTranslation() + + return ( + + +
+ } css={{ color: "#DFB1F3" }} /> + + {t("referenda.empty.title")} + +
+
+ + + +
+ + {t("referenda.empty.desc.first")} + + + {t("referenda.empty.desc.second")} + +
+
+ ) +} diff --git a/src/components/ReferendumCard/Referenda.tsx b/src/components/ReferendumCard/Referenda.tsx new file mode 100644 index 000000000..322d9c978 --- /dev/null +++ b/src/components/ReferendumCard/Referenda.tsx @@ -0,0 +1,263 @@ +import { TReferenda, useReferendumInfo } from "api/democracy" +//import Calendar from "assets/icons/Calendar.svg?react" +import VoteIcon from "assets/icons/StakingVote.svg?react" +import { Separator } from "components/Separator/Separator" +import { Spacer } from "components/Spacer/Spacer" +import { Text } from "components/Typography/Text/Text" +import { useTranslation } from "react-i18next" +import { BN_0 } from "utils/constants" +import { + SHeader, + SOpenGovContainer, + SProgressBarContainer, + SThresholdLine, + STrackBadge, + SVoteButton, +} from "./ReferendumCard.styled" +import { Icon } from "components/Icon/Icon" +import { LinearProgress } from "components/Progress" +import { theme } from "theme" +import { PalletReferendaReferendumStatus } from "@polkadot/types/lookup" +import { useAssets } from "providers/assets" +import { + getPerbillPercentage, + useMinApprovalThreshold, + useReferendaVotes, + useSupportThreshold, +} from "./Referenda.utils" +import Skeleton from "react-loading-skeleton" + +export const OpenGovReferenda = ({ + id, + referenda, + track, + totalIssuance, +}: { + id: string + referenda: PalletReferendaReferendumStatus + track: TReferenda + totalIssuance?: string +}) => { + const { native } = useAssets() + const { t } = useTranslation() + + const subscanInfo = useReferendumInfo(id) + + const minApprovalThreshold = useMinApprovalThreshold(track, referenda) + const { threshold, maxSupportBarValue, barPercentage, markPercentage } = + useSupportThreshold(track, referenda, "39232343436849789168172" ?? "0") + const votes = useReferendaVotes(referenda) + + const isNoVotes = votes.percAyes.eq(0) && votes.percNays.eq(0) + const isOneWayVote = votes.percAyes.eq(0) || votes.percNays.eq(0) + + return ( + + +
+ {track && } + + + #{id} + +
+
+ + + +
+ {subscanInfo.isLoading ? ( + + ) : ( + + {subscanInfo.data?.title ?? "N/a"} + + )} + + + +
+ +
+ {isNoVotes ? ( + + ) : ( + <> + + + + )} + +
+
+
+
+ + {t("toast.sidebar.referendums.aye")} + +
+ + {t("value.compact", { + value: votes.ayes, + numberSuffix: "HDX", + })} + + + {native.symbol} + + + {t("value.percentage", { + value: votes.percAyes, + numberPrefix: "(", + numberSuffix: "%)", + })} + +
+
+
+ + {t("threshold")} + + + {t("value.percentage", { value: minApprovalThreshold })} + +
+
+ + {t("toast.sidebar.referendums.nay")} + +
+ + {t("value.compact", { value: votes.nays })} + + + {native.symbol} + + + {t("value.percentage", { + value: votes.percNays, + numberPrefix: "(", + numberSuffix: "%)", + })} + +
+
+
+
+ + +
+ +
+ + +
+
+
+
+ + {t("value.percentage", { value: BN_0 })} + +
+ +
+ + {t("threshold")} + + + {getPerbillPercentage(threshold?.toNumber())} + +
+ +
+ + {getPerbillPercentage(maxSupportBarValue)} + +
+
+
+
+ + + +
+ {/*
+ + 🔥. + 25% reduce reward time + + + +
+ } css={{ color: "#DFB1F3" }} /> + + 1 day 24hours left + +
+
*/} + + } /> + {t("referenda.btn.vote")} + +
+
+ ) +} + +const TrackBadge = ({ title }: { title: string }) => { + return {title} +} + +const StateBadge = ({ + referenda, +}: { + referenda: PalletReferendaReferendumStatus +}) => { + const { t } = useTranslation() + let state + + const decisionDeposit = referenda.decisionDeposit.toString() + const deciding = referenda.deciding.unwrapOr(null) + + if (!decisionDeposit || !deciding) { + state = t("referenda.state.preparing") + } else if (!deciding.confirming.toString()) { + state = t("referenda.state.deciding") + } else { + state = t("referenda.state.confirming") + } + + return ( + + {state} + + ) +} diff --git a/src/components/ReferendumCard/Referenda.utils.ts b/src/components/ReferendumCard/Referenda.utils.ts new file mode 100644 index 000000000..661fff3dd --- /dev/null +++ b/src/components/ReferendumCard/Referenda.utils.ts @@ -0,0 +1,155 @@ +import { useBestNumber } from "api/chain" +import { useMemo } from "react" +import { getCurveData, getDecidingEndPercentage } from "utils/opengov" +import BN from "bignumber.js" +import { PalletReferendaReferendumStatus } from "@polkadot/types/lookup" +import { BN_0, BN_NAN } from "utils/constants" +import { isNil } from "utils/helpers" +import { TReferenda } from "api/democracy" + +export const getPerbillPercentage = (perbill = 0) => { + if (isNil(perbill) || perbill <= 0) { + return "0.0%" + } + + const precision = perbill > 10 * Math.pow(10, 7) ? 1 : 2 + return ((perbill / Math.pow(10, 9)) * 100).toFixed(precision) + "%" +} + +export const useMinApprovalThreshold = ( + track: TReferenda, + referenda: PalletReferendaReferendumStatus, +) => { + const { data: blockNumbers } = useBestNumber() + const blockNumber = blockNumbers?.parachainBlockNumber + .toBigNumber() + // basilisk block number calculated from hydra nice rpc + .plus(4588976) + .toString() + + return useMemo(() => { + if (track && blockNumber) { + const isDecidingSince = + referenda.deciding.unwrapOr(null)?.since.toString() ?? "0" + + const percentage = getDecidingEndPercentage( + track.decisionPeriod.toString(), + isDecidingSince.toString(), + blockNumber, + ) + + const getApprovalThreshold = getCurveData(track, "minApproval") + + return BN(getApprovalThreshold?.(percentage.toNumber()) ?? BN_NAN).times( + 100, + ) + } + }, [track, blockNumber, referenda]) +} + +export const useReferendaVotes = ( + referenda: PalletReferendaReferendumStatus, +) => { + return useMemo(() => { + if (!referenda) + return { ayes: BN_0, nays: BN_0, percAyes: BN_0, percNays: BN_0 } + + const ayes = referenda.tally.ayes.toBigNumber().shiftedBy(-12) + const nays = referenda.tally.nays.toBigNumber().shiftedBy(-12) + + const votesSum = ayes.plus(nays) + + let percAyes = BN_0 + let percNays = BN_0 + + if (!votesSum.isZero()) { + percAyes = ayes.div(votesSum).times(100) + percNays = nays.div(votesSum).times(100) + } + + return { ayes, nays, percAyes, percNays } + }, [referenda]) +} + +export const useSupportThreshold = ( + track: TReferenda, + referenda: PalletReferendaReferendumStatus, + issuance: string, +) => { + const { data: blockNumbers } = useBestNumber() + const blockNumber = blockNumbers?.parachainBlockNumber + .toBigNumber() + // basilisk block number calculated from hydra nice rpc + .plus(4588976) + .toString() + + const support = useMemo( + () => + BN(referenda.tally.support.toString()) + .div(issuance) + .multipliedBy(Math.pow(10, 9)) + .toNumber(), + [issuance, referenda.tally.support], + ) + + const supportThreshold = useMemo(() => { + if (track && blockNumber) { + const isDecidingSince = + referenda.deciding.unwrapOr(null)?.since.toString() ?? "0" + + const percentage = getDecidingEndPercentage( + track.decisionPeriod.toString(), + isDecidingSince.toString(), + blockNumber, + ) + + const getApprovalThreshold = getCurveData(track, "minSupport") + + return BN(getApprovalThreshold?.(percentage.toNumber()) ?? BN_NAN) + } + }, [track, blockNumber, referenda]) + + const threshold = useMemo( + () => supportThreshold?.shiftedBy(9), + [supportThreshold], + ) + + const maxSupportBarValue = useMemo( + () => + BN.max(support, threshold?.toNumber() ?? 0) + .multipliedBy(1.25) + .toNumber(), + [support, threshold], + ) + + const barPercentage = useMemo(() => { + if (!support || !maxSupportBarValue) { + return 0 + } + + // when the decision period reach end, we show 100% for support bar, + // because support threshold require 0% at the end + if (maxSupportBarValue <= 0) { + return 100 + } + + return BN(support).div(maxSupportBarValue).times(100).toNumber() + }, [support, maxSupportBarValue]) + + const markPercentage = useMemo(() => { + if (!maxSupportBarValue || !threshold) { + return 0 + } + + return threshold.div(maxSupportBarValue).times(100).toNumber() + }, [threshold, maxSupportBarValue]) + + return { + support, + supportThreshold, + threshold, + maxSupportBarValue, + barPercentage, + markPercentage, + } +} diff --git a/src/components/ReferendumCard/ReferendaSkeleton.tsx b/src/components/ReferendumCard/ReferendaSkeleton.tsx new file mode 100644 index 000000000..653427531 --- /dev/null +++ b/src/components/ReferendumCard/ReferendaSkeleton.tsx @@ -0,0 +1,64 @@ +import Skeleton from "react-loading-skeleton" +import { + SHeader, + SOpenGovContainer, + SProgressBarContainer, + SVoteButton, +} from "./ReferendumCard.styled" +import { Separator } from "components/Separator/Separator" +import { Spacer } from "components/Spacer/Spacer" +import { Icon } from "components/Icon/Icon" +import { useTranslation } from "react-i18next" +import VoteIcon from "assets/icons/StakingVote.svg?react" + +export const ReferendaSkeleton = () => { + const { t } = useTranslation() + + return ( + + + + + + + +
+ + + + + +
span": { width: "100%", position: "relative", top: -7 }, + }} + > + + +
+
+ + + + +
span": { width: "100%", position: "relative", top: -7 }, + }} + > + +
+
+
+ + + + + } /> + {t("referenda.btn.vote")} + +
+ ) +} diff --git a/src/components/ReferendumCard/ReferendumCard.styled.ts b/src/components/ReferendumCard/ReferendumCard.styled.ts index 77b08a7a3..cd618fc94 100644 --- a/src/components/ReferendumCard/ReferendumCard.styled.ts +++ b/src/components/ReferendumCard/ReferendumCard.styled.ts @@ -1,5 +1,6 @@ import { css } from "@emotion/react" import styled from "@emotion/styled" +import { ButtonTransparent } from "components/Button/Button" import { theme } from "theme" export const SContainer = styled.a<{ type: "staking" | "toast" }>` @@ -56,6 +57,8 @@ export const SHeader = styled.div` display: flex; align-items: center; justify-content: space-between; + + padding: 0 16px; ` export const SVotedBage = styled.div` @@ -75,3 +78,75 @@ export const SVotedBage = styled.div` padding: 4px 8px; ` + +export const SOpenGovContainer = styled.div<{ type: "staking" | "toast" }>` + padding: 16px 0px; + ${({ type }) => + type === "toast" + ? css` + border-radius: ${theme.borderRadius.default}px; + ` + : css` + border-radius: 16px; + border: 1px solid #372244; + + position: relative; + `} + + background: #240e32; +` + +export const STrackBadge = styled.div` + display: flex; + padding: 6px 8px; + + align-items: center; + gap: 4px; + + border-radius: 32px; + + font-size: 11px; + text-transform: uppercase; + color: ${theme.colors.brightBlue100}; + + background-color: rgba(133, 209, 255, 0.2); +` + +export const SVoteButton = styled(ButtonTransparent)` + border-radius: 32px; + background: #372244; + + width: 82px; + height: 38px; + + color: ${theme.colors.white}; + font-size: 12px; + text-transform: uppercase; + + gap: 8px; + + &:hover { + opacity: 0.7; + } + &:active { + opacity: 0.8; + } +` + +export const SProgressBarContainer = styled.div` + padding: 7px 11px; + + background: rgba(77, 82, 95, 0.1); + + border-radius: 12px; + border: 1px solid rgba(124, 127, 138, 0.2); +` + +export const SThresholdLine = styled.div<{ percentage: string }>` + position: absolute; + top: -10px; + background: #dfb1f3; + width: 1px; + height: 32px; + left: ${({ percentage }) => percentage}%; +` diff --git a/src/components/Toast/sidebar/group/ToastSidebarGroup.tsx b/src/components/Toast/sidebar/group/ToastSidebarGroup.tsx index ee6dcbb97..0f75a88cd 100644 --- a/src/components/Toast/sidebar/group/ToastSidebarGroup.tsx +++ b/src/components/Toast/sidebar/group/ToastSidebarGroup.tsx @@ -11,11 +11,11 @@ import { SToggle, } from "./ToastSidebarGroup.styled" -type Props = { title: string; children: ReactNode } +type Props = { title: string; children: ReactNode; open?: boolean } -export const ToastSidebarGroup = ({ title, children }: Props) => { +export const ToastSidebarGroup = ({ title, children, open = true }: Props) => { const { t } = useTranslation() - const [isOpen, toggle] = useToggle(true) + const [isOpen, toggle] = useToggle(open) return (
diff --git a/src/components/Toast/sidebar/referendums/ToastSidebarReferendums.tsx b/src/components/Toast/sidebar/referendums/ToastSidebarReferendums.tsx index dd94a2e63..20665430b 100644 --- a/src/components/Toast/sidebar/referendums/ToastSidebarReferendums.tsx +++ b/src/components/Toast/sidebar/referendums/ToastSidebarReferendums.tsx @@ -1,40 +1,42 @@ -import { useReferendums } from "api/democracy" -import { ReferendumCard } from "components/ReferendumCard/ReferendumCard" -import { useTranslation } from "react-i18next" +import { + TReferenda, + useOpenGovReferendas, + useReferendaTracks, +} from "api/democracy" +import { OpenGovReferenda } from "components/ReferendumCard/Referenda" +import { useHDXSupplyFromSubscan } from "api/staking" import { ToastSidebarGroup } from "components/Toast/sidebar/group/ToastSidebarGroup" -import { useProviderRpcUrlStore } from "api/provider" -import { ReferendumCardRococo } from "components/ReferendumCard/ReferendumCardRococo" +import { useTranslation } from "react-i18next" export const ToastSidebarReferendums = () => { const { t } = useTranslation() - const referendums = useReferendums("ongoing") - const providers = useProviderRpcUrlStore() - const rococoProvider = [ - "hydradx-rococo-rpc.play.hydration.cloud", - "mining-rpc.hydradx.io", - ].find( - (rpc) => - (providers.rpcUrl ?? import.meta.env.VITE_PROVIDER_URL) === - `wss://${rpc}`, - ) - - if (!referendums.data?.length) return null + const openGovQuery = useOpenGovReferendas() + const tracks = useReferendaTracks() + const HDXSupply = useHDXSupplyFromSubscan() return ( - +
- {referendums.data.map((referendum) => - rococoProvider ? ( - - ) : ( - - ), - )} + {openGovQuery.data?.length && tracks.data + ? openGovQuery.data.map((referendum) => { + const track = tracks.data.get( + referendum.referendum.track.toString(), + ) as TReferenda + + return ( + + ) + }) + : null}
) diff --git a/src/i18n/locales/en/translations.json b/src/i18n/locales/en/translations.json index fe0c96a66..4e8241387 100644 --- a/src/i18n/locales/en/translations.json +++ b/src/i18n/locales/en/translations.json @@ -16,6 +16,7 @@ "close": "Close", "submit": "Submit", "transfer": "Transfer", + "threshold": "Threshold", "24Volume": "24h volume", "duration.left": "{{duration}} left", "duration.ago": "{{duration}} ago", @@ -1098,5 +1099,13 @@ "memepad.summary.adminRights.burn": "Burn admin rights", "memepad.summary.adminRights.burned": "Admin rights revoked", "memepad.summary.adminRights.toast.onLoading": "Revoking admin rights...", - "memepad.summary.adminRights.toast.onSuccess": "Admin rights revoked." + "memepad.summary.adminRights.toast.onSuccess": "Admin rights revoked.", + "referenda.ongoing": "Ongoing Referenda", + "referenda.empty.title": "No Referenda", + "referenda.empty.desc.first": "Nothing here.", + "referenda.empty.desc.second": " Currently there are no ongoing referenda to vote in.", + "referenda.btn.vote": "Vote", + "referenda.state.preparing": "Preparing", + "referenda.state.deciding": "Deciding", + "referenda.state.confirming": "Confirming" } diff --git a/src/sections/staking/StakingPage.utils.ts b/src/sections/staking/StakingPage.utils.ts index 6295667e7..870e1711b 100644 --- a/src/sections/staking/StakingPage.utils.ts +++ b/src/sections/staking/StakingPage.utils.ts @@ -5,18 +5,16 @@ import { useAccount } from "sections/web3-connect/Web3Connect.utils" import { TAccumulatedRpsUpdated, TStakingPosition, - useCirculatingSupply, + useHDXSupplyFromSubscan, useStake, useStakingConsts, useStakingEvents, - useStakingPositionBalances, } from "api/staking" import { useTokenBalance, useTokenLocks } from "api/balances" import { getHydraAccountAddress } from "utils/api" import { useDisplayPrice } from "utils/displayAsset" import { BN_0, - BN_100, BN_BILL, BN_QUINTILL, PARACHAIN_BLOCK_TIME, @@ -96,15 +94,11 @@ export const useStakeData = () => { const { account } = useAccount() const stake = useStake(account?.address) - const circulatingSupply = useCirculatingSupply() + const HDXSupply = useHDXSupplyFromSubscan() const balance = useTokenBalance(native.id, account?.address) const locks = useTokenLocks(native.id) const spotPrice = useDisplayPrice(native.id) - const positionBalances = useStakingPositionBalances( - stake.data?.positionId?.toString(), - ) - const referendas = useReferendums("finished") - + const circulatingSupply = HDXSupply.data?.available_balance const vestLocks = locks.data?.reduce( (acc, lock) => (lock.type === "ormlvest" ? acc.plus(lock.amount) : acc), BN_0, @@ -122,15 +116,7 @@ export const useStakeData = () => { const availableBalance = BigNumber.max(0, rawAvailableBalance ?? BN_0) - const queries = [ - stake, - circulatingSupply, - balance, - locks, - spotPrice, - positionBalances, - referendas, - ] + const queries = [stake, HDXSupply, balance, locks, spotPrice] const isLoading = queries.some((query) => query.isInitialLoading) @@ -144,7 +130,7 @@ export const useStakeData = () => { const totalStake = stake.data?.totalStake ?? 0 const supplyStaked = BN(totalStake) - .div(Number(circulatingSupply.data ?? 1)) + .div(Number(circulatingSupply ?? 1)) .decimalPlaces(4) .multipliedBy(100) @@ -152,68 +138,11 @@ export const useStakeData = () => { .multipliedBy(spotPrice.data?.spotPrice ?? 1) .shiftedBy(-native.decimals) - const circulatingSupplyData = BN(circulatingSupply.data ?? 0).shiftedBy( + const circulatingSupplyData = BN(circulatingSupply ?? 0).shiftedBy( -native.decimals, ) const stakePosition = stake.data?.stakePosition - let averagePercentage = BN_0 - let amountOfReferends = 0 - - if (stakePosition) { - const initialPositionBalance = BN( - positionBalances.data?.events.find( - (event) => event.name === "Staking.PositionCreated", - )?.args.stake ?? 0, - ) - - const allReferendaPercentages = - referendas.data?.reduce((acc, referenda) => { - const endReferendaBlockNumber = - referenda.referendum.asFinished.end.toBigNumber() - - if (endReferendaBlockNumber.gt(stakePosition.createdAt)) { - amountOfReferends++ - - if (referenda.amount && referenda.conviction) { - /* staked position value when a referenda is over */ - let positionBalance = initialPositionBalance - - positionBalances.data?.events.forEach((event) => { - if (event.name === "Staking.StakeAdded") { - const eventOccurBlockNumber = BN(event.block.height) - - if ( - endReferendaBlockNumber.gte(eventOccurBlockNumber) && - positionBalance.lt(event.args.totalStake) - ) { - positionBalance = BN(event.args.totalStake) - } - } - }) - - const percentageOfVotedReferenda = referenda.amount - .div(positionBalance) - .multipliedBy(CONVICTIONS[referenda.conviction.toLowerCase()]) - .div(CONVICTIONS["locked6x"]) - .multipliedBy(100) - - return acc.plus(percentageOfVotedReferenda) - } - } - - return acc - }, BN_0) ?? BN(0) - - averagePercentage = - allReferendaPercentages.isZero() && !amountOfReferends - ? BN_100 - : allReferendaPercentages.div(amountOfReferends) - } - - const rewardBoostPersentage = referendas.data?.length - ? averagePercentage - : BN_100 return { supplyStaked, @@ -226,16 +155,13 @@ export const useStakeData = () => { stakePosition: stakePosition ? { ...stake.data?.stakePosition, - rewardBoostPersentage, } : undefined, } }, [ availableBalance, - circulatingSupply.data, + circulatingSupply, isLoading, - positionBalances.data?.events, - referendas.data, spotPrice.data?.spotPrice, stake.data?.minStake, stake.data?.positionId, diff --git a/src/sections/staking/sections/dashboard/StakingDashboard.tsx b/src/sections/staking/sections/dashboard/StakingDashboard.tsx index 7e95e4a79..7db11d359 100644 --- a/src/sections/staking/sections/dashboard/StakingDashboard.tsx +++ b/src/sections/staking/sections/dashboard/StakingDashboard.tsx @@ -3,7 +3,7 @@ import { AvailableRewards } from "./components/AvailableRewards/AvailableRewards import { StakingInputSection } from "./components/StakingInputSection/StakingInputSection" import { useAccount } from "sections/web3-connect/Web3Connect.utils" import { Stats } from "./components/Stats/Stats" -import { Referenda, ReferendaWrapper } from "./components/Referenda/Referenda" +import { OpenGovReferendas, Referenda } from "./components/Referenda/Referendas" import { useStakeData } from "sections/staking/StakingPage.utils" import { useRpcProvider } from "providers/rpcProvider" import { useMedia } from "react-use" @@ -51,7 +51,7 @@ export const StakingData = () => { {showGuide && } {account && staking.data?.positionId && } - {!isDesktop && } + {!isDesktop && }
{ css={{ flex: 2 }} > - {isDesktop && } + {isDesktop && }
) diff --git a/src/sections/staking/sections/dashboard/components/Referenda/Referenda.tsx b/src/sections/staking/sections/dashboard/components/Referenda/Referenda.tsx deleted file mode 100644 index 5dff50e83..000000000 --- a/src/sections/staking/sections/dashboard/components/Referenda/Referenda.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import { useReferendums } from "api/democracy" -import { ReferendumCard } from "components/ReferendumCard/ReferendumCard" -import { ReferendumCardSkeleton } from "components/ReferendumCard/ReferendumCardSkeleton" -import { Text } from "components/Typography/Text/Text" -import { useTranslation } from "react-i18next" -import { SContainer } from "sections/staking/StakingPage.styled" -import GovernanceIcon from "assets/icons/GovernanceIcon.svg?react" -import { Icon } from "components/Icon/Icon" -import { ReferendumCardRococo } from "components/ReferendumCard/ReferendumCardRococo" -import { useProviderRpcUrlStore } from "api/provider" -import { theme } from "theme" - -type ReferendaProps = { - loading: boolean - data?: ReturnType["data"] -} - -export const ReferendaWrapper = () => { - const referendums = useReferendums("ongoing") - - return -} - -export const Referenda = ({ data, loading }: ReferendaProps) => { - const { t } = useTranslation() - const providers = useProviderRpcUrlStore() - const rococoProvider = [ - "hydradx-rococo-rpc.play.hydration.cloud", - "mining-rpc.hydradx.io", - ].find( - (rpc) => - (providers.rpcUrl ?? import.meta.env.VITE_PROVIDER_URL) === - `wss://${rpc}`, - ) - - return ( - - - {t("stats.overview.referenda.title")} - - {loading ? ( - - ) : data?.length ? ( -
- - {t("stats.overview.referenda.desc")} - - {data.map((referendum) => - rococoProvider ? ( - - ) : ( - - ), - )} -
- ) : ( -
- } /> - - {t("stats.overview.referenda.emptyState")} - -
- )} -
- ) -} diff --git a/src/sections/staking/sections/dashboard/components/Referenda/Referendas.tsx b/src/sections/staking/sections/dashboard/components/Referenda/Referendas.tsx new file mode 100644 index 000000000..6556d9e71 --- /dev/null +++ b/src/sections/staking/sections/dashboard/components/Referenda/Referendas.tsx @@ -0,0 +1,187 @@ +import { + TReferenda, + useOpenGovReferendas, + useReferendaTracks, + useReferendums, +} from "api/democracy" +import { ReferendumCard } from "components/ReferendumCard/ReferendumCard" +import { ReferendumCardSkeleton } from "components/ReferendumCard/ReferendumCardSkeleton" +import { Text } from "components/Typography/Text/Text" +import { useTranslation } from "react-i18next" +import { SContainer } from "sections/staking/StakingPage.styled" +import GovernanceIcon from "assets/icons/GovernanceIcon.svg?react" +import { Icon } from "components/Icon/Icon" +import { ReferendumCardRococo } from "components/ReferendumCard/ReferendumCardRococo" +import { useProviderRpcUrlStore } from "api/provider" +import { theme } from "theme" +import { useHDXSupplyFromSubscan } from "api/staking" +import { + Dropdown, + DropdownTriggerContent, +} from "components/Dropdown/DropdownRebranded" +import { useMemo, useState } from "react" +import { OpenGovReferenda } from "components/ReferendumCard/Referenda" +import { NoReferenda } from "components/ReferendumCard/NoReferenda" +import { ReferendaSkeleton } from "components/ReferendumCard/ReferendaSkeleton" + +const defaultFilter = { key: "all", label: "ALL" } + +type ReferendaProps = { + loading: boolean + data?: ReturnType["data"] +} + +export const ReferendaWrapper = () => { + const referendums = useReferendums("ongoing") + + return +} + +export const Referenda = ({ data, loading }: ReferendaProps) => { + const { t } = useTranslation() + const providers = useProviderRpcUrlStore() + const rococoProvider = [ + "hydradx-rococo-rpc.play.hydration.cloud", + "mining-rpc.hydradx.io", + ].find( + (rpc) => + (providers.rpcUrl ?? import.meta.env.VITE_PROVIDER_URL) === + `wss://${rpc}`, + ) + + return ( + + + {t("stats.overview.referenda.title")} + + {loading ? ( + + ) : data?.length ? ( +
+ + {t("stats.overview.referenda.desc")} + + {data.map((referendum) => + rococoProvider ? ( + + ) : ( + + ), + )} +
+ ) : ( +
+ } /> + + {t("stats.overview.referenda.emptyState")} + +
+ )} +
+ ) +} + +export const OpenGovReferendas = () => { + const { t } = useTranslation() + const openGovQuery = useOpenGovReferendas() + const tracks = useReferendaTracks() + const HDXSupply = useHDXSupplyFromSubscan() + + const [filter, setFilter] = useState(defaultFilter.key) + + const trackItems = useMemo( + () => + tracks.data + ? [ + defaultFilter, + ...Array.from(tracks.data.entries()).map((track) => ({ + key: track[0], + label: track[1].nameHuman, + })), + ].sort((a, b) => a.label.localeCompare(b.label)) + : null, + [tracks.data], + ) + + const filtredReferenda = useMemo(() => { + if (openGovQuery.data?.length && trackItems) { + if (filter !== defaultFilter.key) { + return openGovQuery.data.filter( + (referenda) => referenda.referendum.track.toString() === filter, + ) + } else { + return openGovQuery.data + } + } + }, [openGovQuery.data, trackItems, filter]) + + const isLoading = + openGovQuery.isLoading || HDXSupply.isLoading || tracks.isLoading + + return ( +
+
+ + Ongoing referenda + + {trackItems && ( + setFilter(item.key)} + > + item.key === filter)?.label} + /> + + )} +
+ + {isLoading ? ( + + ) : ( +
+ {filtredReferenda?.length && tracks.data ? ( + filtredReferenda.map((referendum) => { + const track = tracks.data.get( + referendum.referendum.track.toString(), + ) as TReferenda + + return ( + + ) + }) + ) : ( + + )} +
+ )} + + {t("stats.overview.referenda.desc")} + +
+ ) +} diff --git a/src/utils/formatting.ts b/src/utils/formatting.ts index de7abebf4..a62776e08 100644 --- a/src/utils/formatting.ts +++ b/src/utils/formatting.ts @@ -394,3 +394,7 @@ export function createSubscanLink( return "" } } + +export const humanizeUnderscoredString = (value: string) => { + return value.split("_").join(" ").toUpperCase() +} diff --git a/src/utils/opengov.ts b/src/utils/opengov.ts new file mode 100644 index 000000000..242185ebe --- /dev/null +++ b/src/utils/opengov.ts @@ -0,0 +1,82 @@ +import BigNumber from "bignumber.js" +import { TReferenda } from "api/democracy" + +export const getCurveData = ( + track: TReferenda, + field: "minApproval" | "minSupport", +) => { + const curve = track[field] + + if (!curve) { + return null + } + + if (curve.isReciprocal) { + const { factor, xOffset, yOffset } = curve.asReciprocal + return makeReciprocalCurve( + factor.toString(), + xOffset.toString(), + yOffset.toString(), + ) + } + + if (curve.isLinearDecreasing) { + const { length, floor, ceil } = curve.asLinearDecreasing + + return makeLinearCurve(length.toNumber(), floor.toNumber(), ceil.toNumber()) + } + + return null +} + +export const makeReciprocalCurve = ( + factor: string, + xOffset: string, + yOffset: string, +) => { + return (percentage: number) => { + const x = percentage * Math.pow(10, 9) + + const v = new BigNumber(factor) + .div(new BigNumber(x).plus(xOffset)) + .multipliedBy(Math.pow(10, 9)) + .toFixed(0, BigNumber.ROUND_DOWN) + + const calcValue = new BigNumber(v) + .plus(yOffset) + .div(Math.pow(10, 9)) + .toString() + return BigNumber.max(calcValue, 0).toString() + } +} + +export const makeLinearCurve = ( + length: number, + floor: number, + ceil: number, +) => { + return (percentage: number) => { + const x = percentage * Math.pow(10, 9) + + const xValue = BigNumber.min(x, length) + + const slope = new BigNumber(ceil).minus(floor).dividedBy(length) + const deducted = slope.multipliedBy(xValue).toString() + + const perbill = new BigNumber(ceil) + .minus(deducted) + .toFixed(0, BigNumber.ROUND_DOWN) + const calcValue = new BigNumber(perbill).div(Math.pow(10, 9)).toString() + return BigNumber.max(calcValue, 0).toString() + } +} + +export const getDecidingEndPercentage = ( + decisionPeriod: string, + decidingSince: string, + endHeight: string, +) => { + const gone = BigNumber(endHeight).minus(decidingSince) + + return BigNumber.min(gone.div(decisionPeriod), 1) +} diff --git a/src/utils/queryKeys.ts b/src/utils/queryKeys.ts index 8268746c7..2eb5b5f03 100644 --- a/src/utils/queryKeys.ts +++ b/src/utils/queryKeys.ts @@ -245,12 +245,14 @@ export const QUERY_KEYS = { accountAddress, type, ], + openGovReferendas: ["openGovReferendas"], + referendaTracks: ["referendaTracks"], referendumVotes: (accountAddress?: string) => [ QUERY_KEY_PREFIX, "referendumVotes", accountAddress, ], - referendumInfo: (id: string) => [QUERY_KEY_PREFIX, id, "referendumInfo"], + referendumInfo: (id: string) => [id, "referendumInfo"], stats: ( type: ChartType, timeframe?: StatsTimeframe, @@ -263,16 +265,12 @@ export const QUERY_KEYS = { return key }, - circulatingSupply: ["circulatingSupply"], + hdxSupply: ["hdxSupply"], stake: (address: string | undefined) => ["stake", address], staking: ["staking"], stakingPosition: (id: number | undefined) => ["totalStaking", id], stakingConsts: ["stakingConsts"], stakingEvents: ["stakingEvents"], - stakingPositionBalances: (positionId: Maybe) => [ - "positionBalances", - positionId, - ], stableswapPools: [QUERY_KEY_PREFIX, "stableswapPools"], stableswapPool: (id?: string) => [QUERY_KEY_PREFIX, "stableswapPool", id], lbpPool: ["lbpPool"], From b2af79840e9620dd88baf5d422f763afdd81236a Mon Sep 17 00:00:00 2001 From: vkulinich Date: Thu, 3 Oct 2024 15:14:07 +0200 Subject: [PATCH 02/10] wip --- src/components/ReferendumCard/Referenda.utils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/ReferendumCard/Referenda.utils.ts b/src/components/ReferendumCard/Referenda.utils.ts index 661fff3dd..546756be2 100644 --- a/src/components/ReferendumCard/Referenda.utils.ts +++ b/src/components/ReferendumCard/Referenda.utils.ts @@ -24,7 +24,7 @@ export const useMinApprovalThreshold = ( const blockNumber = blockNumbers?.parachainBlockNumber .toBigNumber() // basilisk block number calculated from hydra nice rpc - .plus(4588976) + .plus(4600287) .toString() return useMemo(() => { @@ -80,7 +80,7 @@ export const useSupportThreshold = ( const blockNumber = blockNumbers?.parachainBlockNumber .toBigNumber() // basilisk block number calculated from hydra nice rpc - .plus(4588976) + .plus(4600287) .toString() const support = useMemo( From aae12599802a5c5be5da979a87e29df250f0c2be Mon Sep 17 00:00:00 2001 From: vkulinich Date: Mon, 7 Oct 2024 10:28:09 +0200 Subject: [PATCH 03/10] wip --- src/components/ReferendumCard/Referenda.utils.ts | 10 ++++------ src/utils/opengov.ts | 5 ++++- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/components/ReferendumCard/Referenda.utils.ts b/src/components/ReferendumCard/Referenda.utils.ts index 546756be2..be0e7f351 100644 --- a/src/components/ReferendumCard/Referenda.utils.ts +++ b/src/components/ReferendumCard/Referenda.utils.ts @@ -29,12 +29,11 @@ export const useMinApprovalThreshold = ( return useMemo(() => { if (track && blockNumber) { - const isDecidingSince = - referenda.deciding.unwrapOr(null)?.since.toString() ?? "0" + const decidingSince = referenda.deciding.unwrapOr(null)?.since.toString() const percentage = getDecidingEndPercentage( track.decisionPeriod.toString(), - isDecidingSince.toString(), + decidingSince, blockNumber, ) @@ -94,12 +93,11 @@ export const useSupportThreshold = ( const supportThreshold = useMemo(() => { if (track && blockNumber) { - const isDecidingSince = - referenda.deciding.unwrapOr(null)?.since.toString() ?? "0" + const decidingSince = referenda.deciding.unwrapOr(null)?.since.toString() const percentage = getDecidingEndPercentage( track.decisionPeriod.toString(), - isDecidingSince.toString(), + decidingSince, blockNumber, ) diff --git a/src/utils/opengov.ts b/src/utils/opengov.ts index 242185ebe..e75ad6aa3 100644 --- a/src/utils/opengov.ts +++ b/src/utils/opengov.ts @@ -1,5 +1,6 @@ import BigNumber from "bignumber.js" import { TReferenda } from "api/democracy" +import { BN_0 } from "./constants" export const getCurveData = ( track: TReferenda, @@ -73,9 +74,11 @@ export const makeLinearCurve = ( export const getDecidingEndPercentage = ( decisionPeriod: string, - decidingSince: string, + decidingSince: string | undefined, endHeight: string, ) => { + if (decidingSince === undefined) return BN_0 + const gone = BigNumber(endHeight).minus(decidingSince) return BigNumber.min(gone.div(decisionPeriod), 1) From b493c920cdc500dad82d424e3f83c036cd21f383 Mon Sep 17 00:00:00 2001 From: vkulinich Date: Thu, 19 Dec 2024 13:52:35 +0100 Subject: [PATCH 04/10] wip --- src/components/ReferendumCard/Referenda.utils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/ReferendumCard/Referenda.utils.ts b/src/components/ReferendumCard/Referenda.utils.ts index be0e7f351..cceae2bb2 100644 --- a/src/components/ReferendumCard/Referenda.utils.ts +++ b/src/components/ReferendumCard/Referenda.utils.ts @@ -24,7 +24,7 @@ export const useMinApprovalThreshold = ( const blockNumber = blockNumbers?.parachainBlockNumber .toBigNumber() // basilisk block number calculated from hydra nice rpc - .plus(4600287) + .plus(859253) .toString() return useMemo(() => { @@ -79,7 +79,7 @@ export const useSupportThreshold = ( const blockNumber = blockNumbers?.parachainBlockNumber .toBigNumber() // basilisk block number calculated from hydra nice rpc - .plus(4600287) + .plus(859253) .toString() const support = useMemo( From ac07264ca21c310f8d5b4c613ebda370a6a74715 Mon Sep 17 00:00:00 2001 From: vkulinich Date: Thu, 19 Dec 2024 16:32:10 +0100 Subject: [PATCH 05/10] clean --- .env.development | 2 +- .env.production | 2 +- .env.rococo | 2 +- src/api/democracy.ts | 23 +-- src/api/staking.ts | 10 +- src/components/ReferendumCard/Referenda.tsx | 29 ++-- .../ReferendumCard/Referenda.utils.ts | 4 - .../ReferendumCard/ReferendumCard.styled.ts | 66 ++------ .../ReferendumCard/ReferendumCard.tsx | 156 ----------------- .../ReferendumCard/ReferendumCardProgress.tsx | 54 ------ .../ReferendumCard/ReferendumCardRococo.tsx | 157 ------------------ .../ReferendumCard/ReferendumCardSkeleton.tsx | 59 ------- .../referendums/ToastSidebarReferendums.tsx | 4 +- src/i18n/locales/en/translations.json | 2 +- .../Warnings/IsolationModeWarning.tsx | 1 - src/sections/staking/StakingPage.utils.ts | 2 +- .../sections/dashboard/StakingDashboard.tsx | 7 +- .../components/Referenda/Referendas.tsx | 82 +-------- .../StakingInputSection/Stake/Stake.tsx | 2 +- .../StakingInputSection/Unstake/Unstake.tsx | 2 +- src/utils/queryKeys.ts | 4 +- 21 files changed, 62 insertions(+), 608 deletions(-) delete mode 100644 src/components/ReferendumCard/ReferendumCard.tsx delete mode 100644 src/components/ReferendumCard/ReferendumCardProgress.tsx delete mode 100644 src/components/ReferendumCard/ReferendumCardRococo.tsx delete mode 100644 src/components/ReferendumCard/ReferendumCardSkeleton.tsx diff --git a/.env.development b/.env.development index bedc6e1fc..f49ee50f1 100644 --- a/.env.development +++ b/.env.development @@ -12,7 +12,7 @@ VITE_STABLECOIN_ASSET_ID=10 VITE_FF_DISPLAY_ASSET_ENABLED=true VITE_FF_ADD_TOKEN=true VITE_REFERENDUM_LINK=https://hydration.subsquare.io/democracy/referendum -VITE_REFERENDUM_DATA_URL=https://hydration.subsquare.io/api/democracy/referendums +VITE_REFERENDUM_DATA_URL=https://hydration.subsquare.io/api/gov2/referendums VITE_EVM_CHAIN_ID=222222 VITE_EVM_NATIVE_ASSET_ID=20 VITE_MIGRATION_TRIGGER_DOMAIN="deploy-preview-1334--testnet-hydra-app.netlify.app" diff --git a/.env.production b/.env.production index 33a14b79c..a51fc6773 100644 --- a/.env.production +++ b/.env.production @@ -12,7 +12,7 @@ VITE_STABLECOIN_ASSET_ID=10 VITE_FF_DISPLAY_ASSET_ENABLED=false VITE_FF_ADD_TOKEN=true VITE_REFERENDUM_LINK=https://hydration.subsquare.io/democracy/referendum -VITE_REFERENDUM_DATA_URL=https://hydration.subsquare.io/api/democracy/referendums +VITE_REFERENDUM_DATA_URL=https://hydration.subsquare.io/api/gov2/referendums VITE_EVM_CHAIN_ID=222222 VITE_EVM_NATIVE_ASSET_ID=20 VITE_MIGRATION_TRIGGER_DOMAIN="app.hydradx.io" diff --git a/.env.rococo b/.env.rococo index f3b60811a..f4e52b5ba 100644 --- a/.env.rococo +++ b/.env.rococo @@ -12,7 +12,7 @@ VITE_STABLECOIN_ASSET_ID=10 VITE_FF_DISPLAY_ASSET_ENABLED=false VITE_FF_ADD_TOKEN=false VITE_REFERENDUM_LINK=https://hydration.subsquare.io/democracy/referendum -VITE_REFERENDUM_DATA_URL=https://hydration.subsquare.io/api/democracy/referendums +VITE_REFERENDUM_DATA_URL=https://hydration.subsquare.io/api/gov2/referendums VITE_EVM_CHAIN_ID= VITE_EVM_NATIVE_ASSET_ID=20 VITE_MIGRATION_TRIGGER_DOMAIN="" diff --git a/src/api/democracy.ts b/src/api/democracy.ts index faf135c68..af3ef045c 100644 --- a/src/api/democracy.ts +++ b/src/api/democracy.ts @@ -12,9 +12,9 @@ import { import BN, { BigNumber } from "bignumber.js" import { BN_0 } from "utils/constants" import { humanizeUnderscoredString } from "utils/formatting" -import { SubstrateApis } from "@galacticcouncil/xcm-core" +import { useActiveRpcUrlList } from "./provider" -const REFERENDUM_DATA_URL = "https://basilisk.subsquare.io/api/gov2/referendums" //import.meta.env.VITE_REFERENDUM_DATA_URL as string +const REFERENDUM_DATA_URL = import.meta.env.VITE_REFERENDUM_DATA_URL as string const CONVICTIONS_BLOCKS: { [key: string]: number } = { none: 0, @@ -72,17 +72,19 @@ export const useReferendumInfo = (referendumIndex: string) => { } export const useOpenGovReferendas = () => { + const rpcUrlList = useActiveRpcUrlList() const { api, isLoaded } = useRpcProvider() - return useQuery(QUERY_KEYS.openGovReferendas, getOpenGovRegerendas(api), { - enabled: isLoaded, - }) + return useQuery( + QUERY_KEYS.openGovReferendas(rpcUrlList.join(".")), + getOpenGovRegerendas(api), + { + enabled: isLoaded, + }, + ) } const getOpenGovRegerendas = (api: ApiPromise) => async () => { - const apiPool = SubstrateApis.getInstance() - const api = await apiPool.api("wss://basilisk-rpc.dwellir.com") - const newReferendumsRaw = await api.query.referenda.referendumInfoFor.entries() @@ -266,13 +268,12 @@ export const getAccountUnlockedVotes = } export const useReferendaTracks = () => { + const rpcUrlList = useActiveRpcUrlList() const { api, isLoaded } = useRpcProvider() return useQuery( - QUERY_KEYS.referendaTracks, + QUERY_KEYS.referendaTracks(rpcUrlList.join(".")), async () => { - const apiPool = SubstrateApis.getInstance() - const api = await apiPool.api("wss://basilisk-rpc.dwellir.com") const tracks = await api.consts.referenda.tracks const data: Map = new Map( diff --git a/src/api/staking.ts b/src/api/staking.ts index c67058ea5..092033593 100644 --- a/src/api/staking.ts +++ b/src/api/staking.ts @@ -51,16 +51,18 @@ export const useHDXSupplyFromSubscan = () => { async () => { const res = await getHDXSupplyFromSubscan()() - const HDXData = res.data.detail["BSX"] - - return HDXData + const data = res.data.detail["HDX"] + return { + totalIssuance: data.total_issuance, + circulatingSupply: data.available_balance, + } }, { retry: 0 }, ) } const getHDXSupplyFromSubscan = () => async () => { - const res = await fetch("https://basilisk.api.subscan.io/api/scan/token") + const res = await fetch("https://hydration.api.subscan.io/api/scan/token") const data: Promise = res.json() diff --git a/src/components/ReferendumCard/Referenda.tsx b/src/components/ReferendumCard/Referenda.tsx index 322d9c978..9136e2ce9 100644 --- a/src/components/ReferendumCard/Referenda.tsx +++ b/src/components/ReferendumCard/Referenda.tsx @@ -1,5 +1,4 @@ import { TReferenda, useReferendumInfo } from "api/democracy" -//import Calendar from "assets/icons/Calendar.svg?react" import VoteIcon from "assets/icons/StakingVote.svg?react" import { Separator } from "components/Separator/Separator" import { Spacer } from "components/Spacer/Spacer" @@ -41,11 +40,11 @@ export const OpenGovReferenda = ({ const { native } = useAssets() const { t } = useTranslation() - const subscanInfo = useReferendumInfo(id) + const { data: subscanInfo, isLoading } = useReferendumInfo(id) const minApprovalThreshold = useMinApprovalThreshold(track, referenda) const { threshold, maxSupportBarValue, barPercentage, markPercentage } = - useSupportThreshold(track, referenda, "39232343436849789168172" ?? "0") + useSupportThreshold(track, referenda, totalIssuance ?? "0") const votes = useReferendaVotes(referenda) const isNoVotes = votes.percAyes.eq(0) && votes.percNays.eq(0) @@ -66,11 +65,11 @@ export const OpenGovReferenda = ({
- {subscanInfo.isLoading ? ( + {isLoading ? ( ) : ( - {subscanInfo.data?.title ?? "N/a"} + {subscanInfo?.title ?? "N/a"} )} @@ -208,20 +207,12 @@ export const OpenGovReferenda = ({
- {/*
- - 🔥. + 25% reduce reward time - - - -
- } css={{ color: "#DFB1F3" }} /> - - 1 day 24hours left - -
-
*/} - + } /> {t("referenda.btn.vote")} diff --git a/src/components/ReferendumCard/Referenda.utils.ts b/src/components/ReferendumCard/Referenda.utils.ts index cceae2bb2..ab25d68c5 100644 --- a/src/components/ReferendumCard/Referenda.utils.ts +++ b/src/components/ReferendumCard/Referenda.utils.ts @@ -23,8 +23,6 @@ export const useMinApprovalThreshold = ( const { data: blockNumbers } = useBestNumber() const blockNumber = blockNumbers?.parachainBlockNumber .toBigNumber() - // basilisk block number calculated from hydra nice rpc - .plus(859253) .toString() return useMemo(() => { @@ -78,8 +76,6 @@ export const useSupportThreshold = ( const { data: blockNumbers } = useBestNumber() const blockNumber = blockNumbers?.parachainBlockNumber .toBigNumber() - // basilisk block number calculated from hydra nice rpc - .plus(859253) .toString() const support = useMemo( diff --git a/src/components/ReferendumCard/ReferendumCard.styled.ts b/src/components/ReferendumCard/ReferendumCard.styled.ts index cd618fc94..0d6e20288 100644 --- a/src/components/ReferendumCard/ReferendumCard.styled.ts +++ b/src/components/ReferendumCard/ReferendumCard.styled.ts @@ -1,58 +1,7 @@ import { css } from "@emotion/react" import styled from "@emotion/styled" -import { ButtonTransparent } from "components/Button/Button" import { theme } from "theme" -export const SContainer = styled.a<{ type: "staking" | "toast" }>` - padding: 16px; - ${({ type }) => - type === "toast" - ? css` - border-radius: ${theme.borderRadius.default}px; - ` - : css` - border-radius: ${theme.borderRadius.medium}px; - - position: relative; - - :before { - content: ""; - position: absolute; - inset: 0; - - border-radius: ${theme.borderRadius.medium}px; - padding: 1px; // a width of the border - - background: linear-gradient( - 180deg, - rgba(152, 176, 214, 0.27) 0%, - rgba(163, 177, 199, 0.15) 66.67%, - rgba(158, 167, 180, 0.2) 100% - ); - -webkit-mask: - linear-gradient(#fff 0 0) content-box, - linear-gradient(#fff 0 0); - -webkit-mask-composite: xor; - mask-composite: exclude; - pointer-events: none; - } - `} - - background: ${theme.colors.darkBlue700}; - - transition: background ${theme.transitions.default}; - - cursor: pointer; - - &:hover { - background: ${theme.colors.darkBlue401}; - } - - &:active { - background: ${theme.colors.darkBlue400}; - } -` - export const SHeader = styled.div` display: flex; align-items: center; @@ -112,10 +61,14 @@ export const STrackBadge = styled.div` background-color: rgba(133, 209, 255, 0.2); ` -export const SVoteButton = styled(ButtonTransparent)` +export const SVoteButton = styled.a<{ disabled: boolean }>` border-radius: 32px; background: #372244; + display: flex; + align-items: center; + justify-content: center; + width: 82px; height: 38px; @@ -125,12 +78,21 @@ export const SVoteButton = styled(ButtonTransparent)` gap: 8px; + cursor: pointer; + &:hover { opacity: 0.7; } &:active { opacity: 0.8; } + + ${({ disabled }) => + disabled && + css` + pointer-events: none; + opacity: 0.2; + `} ` export const SProgressBarContainer = styled.div` diff --git a/src/components/ReferendumCard/ReferendumCard.tsx b/src/components/ReferendumCard/ReferendumCard.tsx deleted file mode 100644 index b2c33fe3e..000000000 --- a/src/components/ReferendumCard/ReferendumCard.tsx +++ /dev/null @@ -1,156 +0,0 @@ -import { PalletDemocracyReferendumInfo } from "@polkadot/types/lookup" -import { useReferendumInfo } from "api/democracy" -import IconArrow from "assets/icons/IconArrow.svg?react" -import GovernanceIcon from "assets/icons/GovernanceIcon.svg?react" -import { Separator } from "components/Separator/Separator" -import { Spacer } from "components/Spacer/Spacer" -import { Text } from "components/Typography/Text/Text" -import { useMemo } from "react" -import { useTranslation } from "react-i18next" -import { BN_0, BN_10, PARACHAIN_BLOCK_TIME } from "utils/constants" -import { SContainer, SHeader, SVotedBage } from "./ReferendumCard.styled" -import { ReferendumCardSkeleton } from "./ReferendumCardSkeleton" -import { ReferendumCardProgress } from "./ReferendumCardProgress" -import { Icon } from "components/Icon/Icon" -import BN from "bignumber.js" -import { useBestNumber } from "api/chain" -import { customFormatDuration } from "utils/formatting" - -const REFERENDUM_LINK = import.meta.env.VITE_REFERENDUM_LINK as string - -type Props = { - id: string - referendum: PalletDemocracyReferendumInfo - type: "toast" | "staking" - voted: boolean -} - -export const ReferendumCard = ({ id, referendum, type, voted }: Props) => { - const { t } = useTranslation() - - const info = useReferendumInfo(id) - const bestNumber = useBestNumber() - - const votes = useMemo(() => { - if (!referendum.isOngoing) - return { ayes: BN_0, nays: BN_0, percAyes: BN_0, percNays: BN_0 } - - const ayes = referendum.asOngoing.tally.ayes - .toBigNumber() - .div(BN_10.pow(12)) - const nays = referendum.asOngoing.tally.nays - .toBigNumber() - .div(BN_10.pow(12)) - - const votesSum = ayes.plus(nays) - - let percAyes = BN_0 - let percNays = BN_0 - - if (!votesSum.isZero()) { - percAyes = ayes.div(votesSum).times(100) - percNays = nays.div(votesSum).times(100) - } - - return { ayes, nays, percAyes, percNays } - }, [referendum]) - - const diff = BN(info?.data?.onchainData.meta.end ?? 0) - .minus(bestNumber.data?.parachainBlockNumber.toBigNumber() ?? 0) - .times(PARACHAIN_BLOCK_TIME) - .toNumber() - const endDate = customFormatDuration({ end: diff * 1000 }) - - return info.isLoading || !info.data ? ( - - ) : ( - - -
- - #{info.data.referendumIndex} - - - {"//"} - - - {endDate && - t(`duration.${endDate.isPositive ? "left" : "ago"}`, { - duration: endDate.duration, - })} - -
- -
- {voted && ( - - {t("toast.sidebar.referendums.voted")} - } - /> - - )} - } /> -
-
- - - - - {info.data.title} - - - - - - - - -
- - {t("toast.sidebar.referendums.aye")} - - - {t("toast.sidebar.referendums.nay")} - -
- - - -
- - {t("toast.sidebar.referendums.value", { - value: votes.ayes, - percent: votes.percAyes, - })} - - - {t("toast.sidebar.referendums.value", { - value: votes.nays, - percent: votes.percNays, - })} - -
-
- ) -} diff --git a/src/components/ReferendumCard/ReferendumCardProgress.tsx b/src/components/ReferendumCard/ReferendumCardProgress.tsx deleted file mode 100644 index e9c906033..000000000 --- a/src/components/ReferendumCard/ReferendumCardProgress.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import BN from "bignumber.js" -import { LinearProgress } from "components/Progress" -import { theme } from "theme" - -export type ReferendumCardProgressProps = { - percAyes: BN - percNays: BN -} - -export const ReferendumCardProgress: React.FC = ({ - percAyes, - percNays, -}) => { - const isNoVotes = percAyes.eq(0) && percNays.eq(0) - return ( -
- {isNoVotes ? ( - - ) : ( - <> - - - - )} -
- ) -} diff --git a/src/components/ReferendumCard/ReferendumCardRococo.tsx b/src/components/ReferendumCard/ReferendumCardRococo.tsx deleted file mode 100644 index 3a25e0502..000000000 --- a/src/components/ReferendumCard/ReferendumCardRococo.tsx +++ /dev/null @@ -1,157 +0,0 @@ -import { PalletDemocracyReferendumInfo } from "@polkadot/types/lookup" -import IconArrow from "assets/icons/IconArrow.svg?react" -import GovernanceIcon from "assets/icons/GovernanceIcon.svg?react" -import { Separator } from "components/Separator/Separator" -import { Spacer } from "components/Spacer/Spacer" -import { Text } from "components/Typography/Text/Text" -import { useMemo } from "react" -import { useTranslation } from "react-i18next" -import { BN_0, BN_10, PARACHAIN_BLOCK_TIME } from "utils/constants" -import { SContainer, SHeader, SVotedBage } from "./ReferendumCard.styled" -import { ReferendumCardProgress } from "./ReferendumCardProgress" -import { Icon } from "components/Icon/Icon" -import { useBestNumber } from "api/chain" -import { customFormatDuration } from "utils/formatting" - -type Props = { - id: string - referendum: PalletDemocracyReferendumInfo - type: "toast" | "staking" - rpc: string - voted: boolean -} - -export const ReferendumCardRococo = ({ - id, - referendum, - type, - rpc, - voted, -}: Props) => { - const { t } = useTranslation() - - const bestNumber = useBestNumber() - - const votes = useMemo(() => { - if (!referendum.isOngoing) - return { ayes: BN_0, nays: BN_0, percAyes: BN_0, percNays: BN_0 } - - const ayes = referendum.asOngoing.tally.ayes - .toBigNumber() - .div(BN_10.pow(12)) - const nays = referendum.asOngoing.tally.nays - .toBigNumber() - .div(BN_10.pow(12)) - - const votesSum = ayes.plus(nays) - - let percAyes = BN_0 - let percNays = BN_0 - - if (!votesSum.isZero()) { - percAyes = ayes.div(votesSum).times(100) - percNays = nays.div(votesSum).times(100) - } - - return { ayes, nays, percAyes, percNays } - }, [referendum]) - - const diff = referendum.asOngoing.end - .toBigNumber() - .minus(bestNumber.data?.parachainBlockNumber.toBigNumber() ?? 0) - .times(PARACHAIN_BLOCK_TIME) - .toNumber() - const endDate = customFormatDuration({ end: diff * 1000 }) - - return ( - - -
- - #{id.toString()} - - - {"//"} - - - {endDate && - t(`duration.${endDate.isPositive ? "left" : "ago"}`, { - duration: endDate.duration, - })} - -
- -
- {voted && ( - - {t("toast.sidebar.referendums.voted")} - } - /> - - )} - } /> -
-
- - - - - For Rococo testnet, please participate in referenda through polkadot.js - apps, please click on this tile - - - - - - - - -
- - {t("toast.sidebar.referendums.aye")} - - - {t("toast.sidebar.referendums.nay")} - -
- - - -
- - {t("toast.sidebar.referendums.value", { - value: votes.ayes, - percent: votes.percAyes, - })} - - - {t("toast.sidebar.referendums.value", { - value: votes.nays, - percent: votes.percNays, - })} - -
-
- ) -} diff --git a/src/components/ReferendumCard/ReferendumCardSkeleton.tsx b/src/components/ReferendumCard/ReferendumCardSkeleton.tsx deleted file mode 100644 index c370d27b7..000000000 --- a/src/components/ReferendumCard/ReferendumCardSkeleton.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import Skeleton from "react-loading-skeleton" -import IconArrow from "assets/icons/IconArrow.svg?react" -import { Separator } from "components/Separator/Separator" -import { SContainer, SHeader } from "./ReferendumCard.styled" -import { Spacer } from "components/Spacer/Spacer" -import { Text } from "components/Typography/Text/Text" -import { useTranslation } from "react-i18next" -import { Icon } from "components/Icon/Icon" - -export const ReferendumCardSkeleton = ({ - type, -}: { - type: "toast" | "staking" -}) => { - const { t } = useTranslation() - - const isToastCard = type === "toast" - - return ( - - - - } /> - - - - - - - - -
span": { width: "100%" } }} - > - - -
- - - -
- - {t("toast.sidebar.referendums.aye")} - - - {t("toast.sidebar.referendums.nay")} - -
- - - -
- - -
-
- ) -} diff --git a/src/components/Toast/sidebar/referendums/ToastSidebarReferendums.tsx b/src/components/Toast/sidebar/referendums/ToastSidebarReferendums.tsx index 20665430b..369f4aae5 100644 --- a/src/components/Toast/sidebar/referendums/ToastSidebarReferendums.tsx +++ b/src/components/Toast/sidebar/referendums/ToastSidebarReferendums.tsx @@ -12,7 +12,7 @@ export const ToastSidebarReferendums = () => { const { t } = useTranslation() const openGovQuery = useOpenGovReferendas() const tracks = useReferendaTracks() - const HDXSupply = useHDXSupplyFromSubscan() + const { data: hdxSupply } = useHDXSupplyFromSubscan() return ( { id={referendum.id} referenda={referendum.referendum} track={track} - totalIssuance={HDXSupply.data?.total_issuance} + totalIssuance={hdxSupply?.totalIssuance} /> ) }) diff --git a/src/i18n/locales/en/translations.json b/src/i18n/locales/en/translations.json index 9117288a4..11802c5d2 100644 --- a/src/i18n/locales/en/translations.json +++ b/src/i18n/locales/en/translations.json @@ -775,7 +775,7 @@ "stats.overview.chart.tvl.label.time": "{{ date, HH:mm}}", "stats.overview.chart.switcher.tvl": "tvl", "stats.overview.chart.switcher.volume": "volume", - "stats.overview.referenda.title": "Referenda", + "stats.overview.referenda.title": "Ongoing referenda", "stats.overview.referenda.desc": "Participate in governance to speed up the rate at which you can claim rewards.", "stats.overview.referenda.emptyState": "Currently there are no ongoing referenda to vote in.", "stats.overview.table.assets.header.title": "Omnipool assets", diff --git a/src/sections/lending/components/transactions/Warnings/IsolationModeWarning.tsx b/src/sections/lending/components/transactions/Warnings/IsolationModeWarning.tsx index 80372ea73..b00b2d718 100644 --- a/src/sections/lending/components/transactions/Warnings/IsolationModeWarning.tsx +++ b/src/sections/lending/components/transactions/Warnings/IsolationModeWarning.tsx @@ -1,5 +1,4 @@ import { Alert } from "components/Alert" -import { Link } from "sections/lending/components/primitives/Link" import { Text } from "components/Typography/Text/Text" interface IsolationModeWarningProps { diff --git a/src/sections/staking/StakingPage.utils.ts b/src/sections/staking/StakingPage.utils.ts index 692703407..026ac1b18 100644 --- a/src/sections/staking/StakingPage.utils.ts +++ b/src/sections/staking/StakingPage.utils.ts @@ -101,7 +101,7 @@ export const useStakeData = () => { const locks = useTokenLocks(native.id) const spotPrice = useDisplayPrice(native.id) - const circulatingSupply = hdxSupply?.available_balance + const circulatingSupply = hdxSupply?.circulatingSupply const balance = accountAssets.data?.accountAssetsMap.get(native.id)?.balance const vestLocks = locks.data?.reduce( diff --git a/src/sections/staking/sections/dashboard/StakingDashboard.tsx b/src/sections/staking/sections/dashboard/StakingDashboard.tsx index 7db11d359..4dec83dcf 100644 --- a/src/sections/staking/sections/dashboard/StakingDashboard.tsx +++ b/src/sections/staking/sections/dashboard/StakingDashboard.tsx @@ -3,11 +3,12 @@ import { AvailableRewards } from "./components/AvailableRewards/AvailableRewards import { StakingInputSection } from "./components/StakingInputSection/StakingInputSection" import { useAccount } from "sections/web3-connect/Web3Connect.utils" import { Stats } from "./components/Stats/Stats" -import { OpenGovReferendas, Referenda } from "./components/Referenda/Referendas" +import { OpenGovReferendas } from "./components/Referenda/Referendas" import { useStakeData } from "sections/staking/StakingPage.utils" import { useRpcProvider } from "providers/rpcProvider" import { useMedia } from "react-use" import { theme } from "theme" +import { ReferendaSkeleton } from "components/ReferendumCard/ReferendaSkeleton" export const StakingDashboard = () => { const { isLoaded } = useRpcProvider() @@ -24,7 +25,7 @@ export const StakingSkeleton = () => {
- {!isDesktop && } + {!isDesktop && }
{ css={{ flex: 2 }} > - {isDesktop && } + {isDesktop && }
) diff --git a/src/sections/staking/sections/dashboard/components/Referenda/Referendas.tsx b/src/sections/staking/sections/dashboard/components/Referenda/Referendas.tsx index 6556d9e71..2d9331f62 100644 --- a/src/sections/staking/sections/dashboard/components/Referenda/Referendas.tsx +++ b/src/sections/staking/sections/dashboard/components/Referenda/Referendas.tsx @@ -2,18 +2,9 @@ import { TReferenda, useOpenGovReferendas, useReferendaTracks, - useReferendums, } from "api/democracy" -import { ReferendumCard } from "components/ReferendumCard/ReferendumCard" -import { ReferendumCardSkeleton } from "components/ReferendumCard/ReferendumCardSkeleton" import { Text } from "components/Typography/Text/Text" import { useTranslation } from "react-i18next" -import { SContainer } from "sections/staking/StakingPage.styled" -import GovernanceIcon from "assets/icons/GovernanceIcon.svg?react" -import { Icon } from "components/Icon/Icon" -import { ReferendumCardRococo } from "components/ReferendumCard/ReferendumCardRococo" -import { useProviderRpcUrlStore } from "api/provider" -import { theme } from "theme" import { useHDXSupplyFromSubscan } from "api/staking" import { Dropdown, @@ -26,75 +17,12 @@ import { ReferendaSkeleton } from "components/ReferendumCard/ReferendaSkeleton" const defaultFilter = { key: "all", label: "ALL" } -type ReferendaProps = { - loading: boolean - data?: ReturnType["data"] -} - -export const ReferendaWrapper = () => { - const referendums = useReferendums("ongoing") - - return -} - -export const Referenda = ({ data, loading }: ReferendaProps) => { - const { t } = useTranslation() - const providers = useProviderRpcUrlStore() - const rococoProvider = [ - "hydradx-rococo-rpc.play.hydration.cloud", - "mining-rpc.hydradx.io", - ].find( - (rpc) => - (providers.rpcUrl ?? import.meta.env.VITE_PROVIDER_URL) === - `wss://${rpc}`, - ) - - return ( - - - {t("stats.overview.referenda.title")} - - {loading ? ( - - ) : data?.length ? ( -
- - {t("stats.overview.referenda.desc")} - - {data.map((referendum) => - rococoProvider ? ( - - ) : ( - - ), - )} -
- ) : ( -
- } /> - - {t("stats.overview.referenda.emptyState")} - -
- )} -
- ) -} - export const OpenGovReferendas = () => { const { t } = useTranslation() const openGovQuery = useOpenGovReferendas() const tracks = useReferendaTracks() - const HDXSupply = useHDXSupplyFromSubscan() + const { data: hdxSupply, isLoading: isSupplyLoading } = + useHDXSupplyFromSubscan() const [filter, setFilter] = useState(defaultFilter.key) @@ -125,7 +53,7 @@ export const OpenGovReferendas = () => { }, [openGovQuery.data, trackItems, filter]) const isLoading = - openGovQuery.isLoading || HDXSupply.isLoading || tracks.isLoading + openGovQuery.isLoading || isSupplyLoading || tracks.isLoading return (
@@ -133,7 +61,7 @@ export const OpenGovReferendas = () => { sx={{ flex: "row", justify: "space-between", gap: 4, align: "center" }} > - Ongoing referenda + {t("stats.overview.referenda.title")} {trackItems && ( { id={referendum.id} referenda={referendum.referendum} track={track} - totalIssuance={HDXSupply.data?.total_issuance} + totalIssuance={hdxSupply?.totalIssuance} /> ) }) diff --git a/src/sections/staking/sections/dashboard/components/StakingInputSection/Stake/Stake.tsx b/src/sections/staking/sections/dashboard/components/StakingInputSection/Stake/Stake.tsx index bbb155cab..de4f76633 100644 --- a/src/sections/staking/sections/dashboard/components/StakingInputSection/Stake/Stake.tsx +++ b/src/sections/staking/sections/dashboard/components/StakingInputSection/Stake/Stake.tsx @@ -98,7 +98,7 @@ export const Stake = ({ } await queryClient.invalidateQueries(QUERY_KEYS.stake(account?.address)) - await queryClient.invalidateQueries(QUERY_KEYS.circulatingSupply) + await queryClient.invalidateQueries(QUERY_KEYS.hdxSupply) refetchAccountAssets() } diff --git a/src/sections/staking/sections/dashboard/components/StakingInputSection/Unstake/Unstake.tsx b/src/sections/staking/sections/dashboard/components/StakingInputSection/Unstake/Unstake.tsx index bb73b75dc..3a1cc3963 100644 --- a/src/sections/staking/sections/dashboard/components/StakingInputSection/Unstake/Unstake.tsx +++ b/src/sections/staking/sections/dashboard/components/StakingInputSection/Unstake/Unstake.tsx @@ -82,7 +82,7 @@ export const Unstake = ({ ) await queryClient.invalidateQueries(QUERY_KEYS.stake(account?.address)) - await queryClient.invalidateQueries(QUERY_KEYS.circulatingSupply) + await queryClient.invalidateQueries(QUERY_KEYS.hdxSupply) refetchAccountAssets() if (!transaction.isError) { diff --git a/src/utils/queryKeys.ts b/src/utils/queryKeys.ts index 89319e0f1..aead753a3 100644 --- a/src/utils/queryKeys.ts +++ b/src/utils/queryKeys.ts @@ -221,8 +221,8 @@ export const QUERY_KEYS = { accountAddress, type, ], - openGovReferendas: ["openGovReferendas"], - referendaTracks: ["referendaTracks"], + openGovReferendas: (url: string) => ["openGovReferendas", url], + referendaTracks: (url: string) => ["referendaTracks", url], referendumVotes: (accountAddress?: string) => [ QUERY_KEY_PREFIX, "referendumVotes", From fb84b9a08aa9e7ff75b056895dd5d2f3fecbcaeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Von=C3=A1=C5=A1ek?= Date: Fri, 20 Dec 2024 13:13:04 +0100 Subject: [PATCH 06/10] Upgrade xcm-cfg 6.0.1 --- package.json | 2 +- yarn.lock | 35 ++++++++++++++++++++++++++++------- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 40f31186d..177afbd9f 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "@galacticcouncil/math-xyk": "^1.0.0", "@galacticcouncil/sdk": "^5.1.0", "@galacticcouncil/ui": "^5.2.3", - "@galacticcouncil/xcm-cfg": "^6.0.0", + "@galacticcouncil/xcm-cfg": "^6.0.1", "@galacticcouncil/xcm-core": "^5.5.0", "@galacticcouncil/xcm-sdk": "^7.0.1", "@hookform/resolvers": "^3.3.4", diff --git a/yarn.lock b/yarn.lock index 1cbee3fff..f0e8d4fb2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2294,10 +2294,10 @@ lit "^3.1.4" ts-debounce "^4.0.0" -"@galacticcouncil/xcm-cfg@^6.0.0": - version "6.0.0" - resolved "https://registry.yarnpkg.com/@galacticcouncil/xcm-cfg/-/xcm-cfg-6.0.0.tgz#098f379d2638c24ba21243a54c8e650617b27915" - integrity sha512-Y+wk1LohE0OJIfqzObtKNLacgTiO5cW0xqRKZEN6uBK3W67fsnms6vBeYdnQXebZn8jLKNxN8bNE6vg/2OoSXA== +"@galacticcouncil/xcm-cfg@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/@galacticcouncil/xcm-cfg/-/xcm-cfg-6.0.1.tgz#04c6b3618d335a031eb312feb1b10af1d68992db" + integrity sha512-GV5LWbUvlOv+5kYjIsyEeEGtrE4aaDMV8N6sKfZCOK7RGZ0fBqsi6DSeRKot//ybvXL4Zy+hXGVM6UnuvGKYRg== dependencies: "@galacticcouncil/xcm-core" "^5.5.0" @@ -11663,7 +11663,7 @@ prelude-ls@^1.2.1: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== -"prettier-fallback@npm:prettier@^3", prettier@^2.8.0, prettier@^3.1.1, prettier@^3.3.2: +"prettier-fallback@npm:prettier@^3": version "3.3.2" resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.2.tgz#03ff86dc7c835f2d2559ee76876a3914cec4a90a" integrity sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA== @@ -11675,6 +11675,11 @@ prettier-linter-helpers@^1.0.0: dependencies: fast-diff "^1.1.2" +prettier@^2.8.0, prettier@^3.1.1, prettier@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.2.tgz#03ff86dc7c835f2d2559ee76876a3914cec4a90a" + integrity sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA== + pretty-format@^27.0.0, pretty-format@^27.0.2, pretty-format@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e" @@ -12984,7 +12989,14 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@6.0.1, strip-ansi@^6.0.0, strip-ansi@^6.0.1, strip-ansi@^7.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@6.0.1, strip-ansi@^6.0.0, strip-ansi@^6.0.1, strip-ansi@^7.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -14003,7 +14015,16 @@ wordwrap@^1.0.0: resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@7.0.0, wrap-ansi@^6.2.0, wrap-ansi@^8.1.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@7.0.0, wrap-ansi@^6.2.0, wrap-ansi@^8.1.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== From 7c2c6745134272c8976e059a764de6d69770ce9d Mon Sep 17 00:00:00 2001 From: vkulinich Date: Fri, 20 Dec 2024 15:21:29 +0100 Subject: [PATCH 07/10] Update volume squid query --- src/api/volume.ts | 105 ++++++++++++++++++++++++---------------------- 1 file changed, 55 insertions(+), 50 deletions(-) diff --git a/src/api/volume.ts b/src/api/volume.ts index 5318b4ae3..3801b8554 100644 --- a/src/api/volume.ts +++ b/src/api/volume.ts @@ -9,8 +9,8 @@ import { PROVIDERS, useActiveProvider } from "./provider" import { u8aToHex } from "@polkadot/util" import { decodeAddress, encodeAddress } from "@polkadot/util-crypto" import { HYDRA_ADDRESS_PREFIX } from "utils/api" -import { useBestNumber } from "./chain" import { millisecondsInHour, millisecondsInMinute } from "date-fns/constants" +import { useRpcProvider } from "providers/rpcProvider" export type TradeType = { name: @@ -263,63 +263,68 @@ const squidUrl = const VOLUME_BLOCK_COUNT = 7200 //24 hours export const useXYKSquidVolumes = (addresses: string[]) => { - const { data: bestNumber } = useBestNumber() + const { api, isLoaded } = useRpcProvider() return useQuery( QUERY_KEYS.xykSquidVolumes(addresses), - bestNumber - ? async () => { - const hexAddresses = addresses.map((address) => - u8aToHex(decodeAddress(address)), - ) - const startBlockNumber = - bestNumber.parachainBlockNumber.toNumber() - VOLUME_BLOCK_COUNT - const { xykPoolHistoricalVolumesByPeriod } = await request<{ - xykPoolHistoricalVolumesByPeriod: { - nodes: { - poolId: string - assetAId: number - assetAVolume: string - assetBId: number - assetBVolume: string - }[] - } - }>( - squidUrl, - gql` - query XykVolume($poolIds: [String!]!, $startBlockNumber: Int!) { - xykPoolHistoricalVolumesByPeriod( - filter: { - poolIds: $poolIds - startBlockNumber: $startBlockNumber - } - ) { - nodes { - poolId - assetAId - assetAVolume - assetBId - assetBVolume - } - } - } - `, - { poolIds: hexAddresses, startBlockNumber }, - ) + async () => { + const hexAddresses = addresses.map((address) => + u8aToHex(decodeAddress(address)), + ) - const { nodes = [] } = xykPoolHistoricalVolumesByPeriod + const endBlockNumber = (await api.derive.chain.bestNumber()).toNumber() + const startBlockNumber = endBlockNumber - VOLUME_BLOCK_COUNT - return nodes.map((node) => ({ - poolId: encodeAddress(node.poolId, HYDRA_ADDRESS_PREFIX), - assetId: node.assetAId.toString(), - assetIdB: node.assetBId.toString(), - volume: node.assetAVolume, - })) + const { xykPoolHistoricalVolumesByPeriod } = await request<{ + xykPoolHistoricalVolumesByPeriod: { + nodes: { + poolId: string + assetAId: number + assetAVolume: string + assetBId: number + assetBVolume: string + }[] } - : undefinedNoop, + }>( + squidUrl, + gql` + query XykVolume( + $poolIds: [String!]! + $startBlockNumber: Int! + $endBlockNumber: Int! + ) { + xykPoolHistoricalVolumesByPeriod( + filter: { + poolIds: $poolIds + startBlockNumber: $startBlockNumber + endBlockNumber: $endBlockNumber + } + ) { + nodes { + poolId + assetAId + assetAVolume + assetBId + assetBVolume + } + } + } + `, + { poolIds: hexAddresses, startBlockNumber, endBlockNumber }, + ) + + const { nodes = [] } = xykPoolHistoricalVolumesByPeriod + + return nodes.map((node) => ({ + poolId: encodeAddress(node.poolId, HYDRA_ADDRESS_PREFIX), + assetId: node.assetAId.toString(), + assetIdB: node.assetBId.toString(), + volume: node.assetAVolume, + })) + }, { - enabled: !!bestNumber && !!addresses.length, + enabled: isLoaded && !!addresses.length, staleTime: millisecondsInHour, refetchInterval: millisecondsInMinute, }, From 9e6278234f7dcab52d07e2f5b5b2ec69e9180881 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20P=C3=A1nik?= Date: Sat, 21 Dec 2024 14:17:01 +0800 Subject: [PATCH 08/10] update dwellir rpc --- src/api/provider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/provider.ts b/src/api/provider.ts index cf2189cbc..da5ab1d03 100644 --- a/src/api/provider.ts +++ b/src/api/provider.ts @@ -50,7 +50,7 @@ export const PROVIDERS: ProviderProps[] = [ }, { name: "Dwellir", - url: "wss://hydradx-rpc.dwellir.com", + url: "wss://hydration-rpc.n.dwellir.com", indexerUrl: "https://explorer.hydradx.cloud/graphql", squidUrl: "https://galacticcouncil.squids.live/hydration-pools:prod/api/graphql", From 5e2ea3a9a0d84c5bc5225d91e1a5bdc037431680 Mon Sep 17 00:00:00 2001 From: vkulinich Date: Fri, 20 Dec 2024 17:13:15 +0100 Subject: [PATCH 09/10] Update query names --- src/api/staking.ts | 10 ++++++---- .../components/AvailableRewards/AvailableRewards.tsx | 6 +++--- .../components/StakingInputSection/Stake/Stake.tsx | 6 +++--- .../components/StakingInputSection/Unstake/Unstake.tsx | 10 +++++----- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/api/staking.ts b/src/api/staking.ts index 092033593..3f02cbeb7 100644 --- a/src/api/staking.ts +++ b/src/api/staking.ts @@ -115,7 +115,7 @@ const getStake = (api: ApiPromise, address: string | undefined) => async () => { const getStakingPosition = (api: ApiPromise, id: number) => async () => { const [position, votesRes] = await Promise.all([ api.query.staking.positions(id), - api.query.staking.positionVotes(id), + api.query.staking.votes(id), ]) const positionData = position.unwrap() @@ -125,6 +125,7 @@ const getStakingPosition = (api: ApiPromise, id: number) => async () => { id: BN amount: BN conviction: string + //@ts-ignore }> = await votesRes.votes.reduce(async (acc, [key, data]) => { const prevAcc = await acc const id = key.toBigNumber() @@ -275,7 +276,7 @@ const getStakingInitializedEvents = (indexerUrl: string) => async () => { } } -export const useProcessedVotesIds = () => { +export const useVotesRewardedIds = () => { const { account } = useAccount() const { api } = useRpcProvider() @@ -284,7 +285,7 @@ export const useProcessedVotesIds = () => { return [] } - const processedVotesRes = await api.query.staking.processedVotes.entries( + const processedVotesRes = await api.query.staking.votesRewarded.entries( account.address, ) @@ -302,7 +303,8 @@ export const usePositionVotesIds = () => { const { api } = useRpcProvider() return useMutation(async (positionId: number) => { - const positionVotesRes = await api.query.staking.positionVotes(positionId) + const positionVotesRes = await api.query.staking.votes(positionId) + //@ts-ignore const positionVotesIds = positionVotesRes.votes.map(([position]) => position.toString(), ) diff --git a/src/sections/staking/sections/dashboard/components/AvailableRewards/AvailableRewards.tsx b/src/sections/staking/sections/dashboard/components/AvailableRewards/AvailableRewards.tsx index e3b0b78e7..1a943254f 100644 --- a/src/sections/staking/sections/dashboard/components/AvailableRewards/AvailableRewards.tsx +++ b/src/sections/staking/sections/dashboard/components/AvailableRewards/AvailableRewards.tsx @@ -19,7 +19,7 @@ import { TOAST_MESSAGES } from "state/toasts" import { theme } from "theme" import { useRpcProvider } from "providers/rpcProvider" import { useAccount } from "sections/web3-connect/Web3Connect.utils" -import { useProcessedVotesIds } from "api/staking" +import { useVotesRewardedIds } from "api/staking" import { BN_0 } from "utils/constants" import { Graph } from "components/Graph/Graph" import { XAxis, YAxis } from "recharts" @@ -37,7 +37,7 @@ export const AvailableRewards = () => { const spotPrice = useDisplayPrice(native.id) const refetch = useRefetchAccountAssets() - const processedVotes = useProcessedVotesIds() + const votesRewarded = useVotesRewardedIds() const { createTransaction } = useStore() const queryClient = useQueryClient() @@ -62,7 +62,7 @@ export const AvailableRewards = () => { return memo }, {} as ToastMessage) - const processedVoteIds = await processedVotes.mutateAsync() + const processedVoteIds = await votesRewarded.mutateAsync() await createTransaction( { diff --git a/src/sections/staking/sections/dashboard/components/StakingInputSection/Stake/Stake.tsx b/src/sections/staking/sections/dashboard/components/StakingInputSection/Stake/Stake.tsx index de4f76633..804009a44 100644 --- a/src/sections/staking/sections/dashboard/components/StakingInputSection/Stake/Stake.tsx +++ b/src/sections/staking/sections/dashboard/components/StakingInputSection/Stake/Stake.tsx @@ -16,7 +16,7 @@ import { TOAST_MESSAGES } from "state/toasts" import { useRpcProvider } from "providers/rpcProvider" import { useAccount } from "sections/web3-connect/Web3Connect.utils" import { Web3ConnectModalButton } from "sections/web3-connect/modal/Web3ConnectModalButton" -import { useProcessedVotesIds } from "api/staking" +import { useVotesRewardedIds } from "api/staking" import { useAssets } from "providers/assets" import { useRefetchAccountAssets } from "api/deposits" @@ -41,7 +41,7 @@ export const Stake = ({ const form = useForm<{ amount: string }>() - const processedVotes = useProcessedVotesIds() + const votesRewarded = useVotesRewardedIds() const onSubmit = async (values: FormValues) => { const amount = getFixedPointAmount(values.amount, 12).toString() @@ -69,7 +69,7 @@ export const Stake = ({ }, {} as ToastMessage) if (isStakePosition) { - const processedVoteIds = await processedVotes.mutateAsync() + const processedVoteIds = await votesRewarded.mutateAsync() transaction = await createTransaction( { diff --git a/src/sections/staking/sections/dashboard/components/StakingInputSection/Unstake/Unstake.tsx b/src/sections/staking/sections/dashboard/components/StakingInputSection/Unstake/Unstake.tsx index 3a1cc3963..6d664c9ca 100644 --- a/src/sections/staking/sections/dashboard/components/StakingInputSection/Unstake/Unstake.tsx +++ b/src/sections/staking/sections/dashboard/components/StakingInputSection/Unstake/Unstake.tsx @@ -14,7 +14,7 @@ import { QUERY_KEYS } from "utils/queryKeys" import { TOAST_MESSAGES } from "state/toasts" import { useRpcProvider } from "providers/rpcProvider" import { useAccount } from "sections/web3-connect/Web3Connect.utils" -import { usePositionVotesIds, useProcessedVotesIds } from "api/staking" +import { usePositionVotesIds, useVotesRewardedIds } from "api/staking" import { useAssets } from "providers/assets" import { useRefetchAccountAssets } from "api/deposits" @@ -41,8 +41,8 @@ export const Unstake = ({ }, }) - const processedVotes = useProcessedVotesIds() - const positionVotes = usePositionVotesIds() + const votesRewarded = useVotesRewardedIds() + const votes = usePositionVotesIds() const onSubmit = async () => { if (!positionId) return null @@ -64,8 +64,8 @@ export const Unstake = ({ return memo }, {} as ToastMessage) - const pendingVoteIds = await positionVotes.mutateAsync(positionId) - const processedVoteIds = await processedVotes.mutateAsync() + const pendingVoteIds = await votes.mutateAsync(positionId) + const processedVoteIds = await votesRewarded.mutateAsync() const voteIds = [...pendingVoteIds, ...processedVoteIds] From 783e1c1b4829b865d43e4580d7bbd50cb53df968 Mon Sep 17 00:00:00 2001 From: vkulinich Date: Mon, 23 Dec 2024 14:25:22 +0100 Subject: [PATCH 10/10] add support label --- src/components/InfoTooltip/InfoTooltip.tsx | 4 ++- src/components/ReferendumCard/Referenda.tsx | 30 +++++++++++++-------- src/i18n/locales/en/translations.json | 1 + 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/components/InfoTooltip/InfoTooltip.tsx b/src/components/InfoTooltip/InfoTooltip.tsx index 3eff52a79..3e8041208 100644 --- a/src/components/InfoTooltip/InfoTooltip.tsx +++ b/src/components/InfoTooltip/InfoTooltip.tsx @@ -9,6 +9,7 @@ type InfoTooltipProps = { children?: ReactNode type?: "default" | "black" side?: Tooltip.TooltipContentProps["side"] + align?: Tooltip.TooltipContentProps["align"] asChild?: boolean preventDefault?: boolean } @@ -18,6 +19,7 @@ export function InfoTooltip({ children, type = "default", side = "bottom", + align = "start", asChild = false, preventDefault, }: InfoTooltipProps) { @@ -49,7 +51,7 @@ export function InfoTooltip({
- -
- - -
-
+ + +
+ + +
+
+
diff --git a/src/i18n/locales/en/translations.json b/src/i18n/locales/en/translations.json index 11802c5d2..211c43e8d 100644 --- a/src/i18n/locales/en/translations.json +++ b/src/i18n/locales/en/translations.json @@ -1244,6 +1244,7 @@ "claimingRange.modal.description1": "After joining a farm, a portion of the accumulated rewards is locked. These rewards unlock over time as you remain in the farm and follow loyalty factor curve", "claimingRange.modal.description2": "Claiming forfeits the locked part of the rewards. Use this setting to tweak your preference over claiming faster or losing less rewards (default). This allows you to compound your rewards with ease.", "referenda.ongoing": "Ongoing Referenda", + "referenda.support": "Support: {{value}}", "referenda.empty.title": "No Referenda", "referenda.empty.desc.first": "Nothing here.", "referenda.empty.desc.second": " Currently there are no ongoing referenda to vote in.",