Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

🗳️ Fix past votes stake recovering #2855

Merged
merged 12 commits into from
Apr 24, 2022
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useMemo } from 'react'

import { LockItem } from '@/accounts/components/AccountItem/components/LockItem'
import { useIsVoteStakeLocked } from '@/accounts/hooks/useIsVoteStakeLocked'
import { isRecoverable } from '@/accounts/model/lockTypes'
import { Balances } from '@/accounts/types'
import { RowGapBlock } from '@/common/components/page/PageContent'
Expand All @@ -23,12 +24,11 @@ export const LocksDetails = ({ balance, address }: LocksDetailsProps) => {
[election, address]
)

const isVoteStakeLocked = useMemo(() => {
const candidate = votes?.find((vote) => vote.castBy === address)?.voteFor
// Lock stake if the vote was cast: in current election or to winning candidate
// Enable stake recovery if election is finished
return !!candidate && (!election?.isFinished || candidate.isCouncilMember)
}, [votes, address, election])
const candidate = useMemo(() => {
return votes?.find((vote) => vote.castBy === address)?.voteFor
}, [votes])

const isVoteStakeLocked = !!useIsVoteStakeLocked(election, candidate)

if (!balance || !balance.locks.length) {
return <TextMedium light>No locks found.</TextMedium>
Expand Down
14 changes: 14 additions & 0 deletions packages/ui/src/accounts/hooks/useIsVoteStakeLocked.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { useMemo } from 'react'

import { LatestElection } from '@/council/types/LatestElection'
import { useIsCouncilMember } from '@/memberships/hooks/useIsCouncilMember'
import { Member } from '@/memberships/types'

export const useIsVoteStakeLocked = (latestElection?: LatestElection, candidate?: Member) => {
const isCouncilMember = useIsCouncilMember(candidate)
RafalPloszka marked this conversation as resolved.
Show resolved Hide resolved
return useMemo(() => {
// Lock stake if the vote was cast: in current election or to winning candidate
// Enable stake recovery if election is finished
return !!candidate && (!latestElection?.isFinished || isCouncilMember)
}, [latestElection, candidate])
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react'

import { AccountInfo } from '@/accounts/components/AccountInfo'
import { useIsVoteStakeLocked } from '@/accounts/hooks/useIsVoteStakeLocked'
import { useMyAccounts } from '@/accounts/hooks/useMyAccounts'
import { RecoverBalanceModalCall, VotingData } from '@/accounts/modals/RecoverBalance'
import { accountOrNamed } from '@/accounts/model/accountOrNamed'
Expand All @@ -10,16 +11,18 @@ import { TextInlineMedium, TokenValue } from '@/common/components/typography'
import { useModal } from '@/common/hooks/useModal'
import { useTransactionStatus } from '@/common/hooks/useTransactionStatus'
import { Vote } from '@/council/types'
import { LatestElection } from '@/council/types/LatestElection'
import { MemberInfo } from '@/memberships/components'

import { PastVoteTableListItem, StakeRecoveringButton } from '../styles'

export interface PastVoteProps {
vote: Vote
latestElection?: LatestElection
$colLayout: string
}

export const PastVote = ({ vote, $colLayout }: PastVoteProps) => {
export const PastVote = ({ vote, latestElection, $colLayout }: PastVoteProps) => {
const { allAccounts } = useMyAccounts()
const { showModal } = useModal()
const { isTransactionPending } = useTransactionStatus()
Expand All @@ -36,7 +39,10 @@ export const PastVote = ({ vote, $colLayout }: PastVoteProps) => {
})
}

const isDisabled = !vote.stakeLocked || isTransactionPending
const isVoteStakeLocked = useIsVoteStakeLocked(latestElection, vote.voteFor)
RafalPloszka marked this conversation as resolved.
Show resolved Hide resolved
// Reflects if the stake has been already released by the member.
const isRecovered = !vote.stakeLocked
const isDisabled = isVoteStakeLocked || isRecovered || isTransactionPending

return (
<PastVoteTableListItem $isPast $colLayout={$colLayout}>
Expand All @@ -48,7 +54,7 @@ export const PastVote = ({ vote, $colLayout }: PastVoteProps) => {
<TextInlineMedium>{!vote.voteFor ? 'Sealed' : 'Unsealed'}</TextInlineMedium>
<TransactionButtonWrapper>
<StakeRecoveringButton size="small" disabled={isDisabled} onClick={onClick}>
{vote.stakeLocked ? 'Recover stake' : 'Stake recovered'}
{isRecovered ? 'Stake recovered' : 'Recover stake'}
</StakeRecoveringButton>
</TransactionButtonWrapper>
</PastVoteTableListItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { RowGapBlock } from '@/common/components/page/PageContent'
import { Pagination } from '@/common/components/Pagination'
import { NotFoundText } from '@/common/components/typography/NotFoundText'
import { useSort } from '@/common/hooks/useSort'
import { useLatestElection } from '@/council/hooks/useLatestElection'
RafalPloszka marked this conversation as resolved.
Show resolved Hide resolved
import { useMyPastVotes } from '@/council/hooks/useMyPastVotes'

import { PastVote } from './PastVote/PastVote'
Expand All @@ -17,6 +18,7 @@ import { PastVoteColumns } from './styles'
export const PastVotesList = () => {
const { order, getSortProps } = useSort<CastVoteOrderByInput>('createdAt')
const { votes, isLoading, pagination } = useMyPastVotes({ order })
const { election: latestElection } = useLatestElection()

if (isLoading) {
return <Loading />
Expand All @@ -38,7 +40,7 @@ export const PastVotesList = () => {
</ListHeaders>
<List>
{votes.map((vote) => (
<PastVote vote={vote} key={vote.id} $colLayout={PastVoteColumns} />
<PastVote vote={vote} latestElection={latestElection} key={vote.id} $colLayout={PastVoteColumns} />
))}
</List>
<Pagination {...pagination} />
Expand Down
6 changes: 4 additions & 2 deletions packages/ui/src/memberships/hooks/useIsCouncilMember.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { useMemo } from 'react'

import { useApi } from '@/common/hooks/useApi'
import { useObservable } from '@/common/hooks/useObservable'

Expand All @@ -7,6 +9,6 @@ export const useIsCouncilMember = (member?: Member) => {
const { api, connectionState } = useApi()
const council = useObservable(api?.query.council.councilMembers(), [connectionState])
const councilMembersIds = council?.map(({ membership_id }) => membership_id.toNumber()) ?? []
const isCouncil = member && councilMembersIds.includes(parseInt(member.id))
return isCouncil

return useMemo(() => member && councilMembersIds.includes(parseInt(member.id)), [member, councilMembersIds])
}