Gov2 lock calcs (per account) (#8537)
* Gov2 lock calcs (per account) * Lock calcs * Individual info * Countdown display * Adjust * With conviction * Optional modules * Formatting adjustments * Add abstain to total value * WithAsbstain override type * Linting * Adjust * Clear expired locks * Check ids length
This commit is contained in:
parent
d1a4583dbe
commit
b7a0ee7900
@ -15,6 +15,7 @@ import React, { useCallback, useContext, useEffect, useMemo, useState } from 're
|
||||
import styled, { ThemeContext } from 'styled-components';
|
||||
|
||||
import { ApiPromise } from '@polkadot/api';
|
||||
import useAccountLocks from '@polkadot/app-referenda/useAccountLocks';
|
||||
import { AddressInfo, AddressSmall, Badge, Button, ChainLock, CryptoType, ExpandButton, Forget, Icon, LinkExternal, Menu, Popup, StatusContext, Tags } from '@polkadot/react-components';
|
||||
import { useAccountInfo, useApi, useBalancesAll, useBestNumber, useCall, useLedger, useStakingInfo, useToggle } from '@polkadot/react-hooks';
|
||||
import { keyring } from '@polkadot/ui-keyring';
|
||||
@ -53,6 +54,11 @@ interface DemocracyUnlockable {
|
||||
ids: BN[];
|
||||
}
|
||||
|
||||
interface ReferendaUnlockable {
|
||||
referendaUnlockTx: SubmittableExtrinsic<'promise'> | null;
|
||||
ids: [classId: BN, refId: BN][];
|
||||
}
|
||||
|
||||
const BAL_OPTS_DEFAULT = {
|
||||
available: false,
|
||||
bonded: false,
|
||||
@ -100,16 +106,38 @@ function calcUnbonding (stakingInfo?: DeriveStakingAccount) {
|
||||
return total;
|
||||
}
|
||||
|
||||
function createClearDemocracyTx (api: ApiPromise, address: string, unlockableIds: BN[]): SubmittableExtrinsic<'promise'> | null {
|
||||
return api.tx.utility
|
||||
function createClearDemocracyTx (api: ApiPromise, address: string, ids: BN[]): SubmittableExtrinsic<'promise'> | null {
|
||||
return api.tx.utility && ids.length
|
||||
? api.tx.utility.batch(
|
||||
unlockableIds
|
||||
ids
|
||||
.map((id) => api.tx.democracy.removeVote(id))
|
||||
.concat(api.tx.democracy.unlock(address))
|
||||
)
|
||||
: null;
|
||||
}
|
||||
|
||||
function createClearReferendaTx (api: ApiPromise, address: string, ids: [BN, BN][], palletReferenda = 'convictionVoting'): SubmittableExtrinsic<'promise'> | null {
|
||||
if (!api.tx.utility || !ids.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const inner = ids.map(([classId, refId]) => api.tx[palletReferenda].removeVote(classId, refId));
|
||||
|
||||
ids
|
||||
.reduce((all: BN[], [classId]) => {
|
||||
if (!all.find((id) => id.eq(classId))) {
|
||||
all.push(classId);
|
||||
}
|
||||
|
||||
return all;
|
||||
}, [])
|
||||
.forEach((classId): void => {
|
||||
inner.push(api.tx[palletReferenda].unlock(classId, address));
|
||||
});
|
||||
|
||||
return api.tx.utility.batch(inner);
|
||||
}
|
||||
|
||||
async function showLedgerAddress (getLedger: () => Ledger, meta: KeyringJson$Meta): Promise<void> {
|
||||
const ledger = getLedger();
|
||||
|
||||
@ -135,7 +163,9 @@ function Account ({ account: { address, meta }, className = '', delegation, filt
|
||||
const multiInfos = useMultisigApprovals(address);
|
||||
const proxyInfo = useProxies(address);
|
||||
const { flags: { isDevelopment, isEditable, isEthereum, isExternal, isHardware, isInjected, isMultisig, isProxied }, genesisHash, identity, name: accName, onSetGenesisHash, tags } = useAccountInfo(address);
|
||||
const [{ democracyUnlockTx }, setUnlockableIds] = useState<DemocracyUnlockable>({ democracyUnlockTx: null, ids: [] });
|
||||
const convictionLocks = useAccountLocks('referenda', 'convictionVoting', address);
|
||||
const [{ democracyUnlockTx }, setDemocracyUnlock] = useState<DemocracyUnlockable>({ democracyUnlockTx: null, ids: [] });
|
||||
const [{ referendaUnlockTx }, setReferandaUnlock] = useState<ReferendaUnlockable>({ ids: [], referendaUnlockTx: null });
|
||||
const [vestingVestTx, setVestingTx] = useState<SubmittableExtrinsic<'promise'> | null>(null);
|
||||
const [isBackupOpen, toggleBackup] = useToggle();
|
||||
const [isDeriveOpen, toggleDerive] = useToggle();
|
||||
@ -172,7 +202,7 @@ function Account ({ account: { address, meta }, className = '', delegation, filt
|
||||
}, [address, api, balancesAll, setBalance, stakingInfo]);
|
||||
|
||||
useEffect((): void => {
|
||||
bestNumber && democracyLocks && setUnlockableIds(
|
||||
bestNumber && democracyLocks && setDemocracyUnlock(
|
||||
(prev): DemocracyUnlockable => {
|
||||
const ids = democracyLocks
|
||||
.filter(({ isFinished, unlockAt }) => isFinished && bestNumber.gt(unlockAt))
|
||||
@ -190,6 +220,25 @@ function Account ({ account: { address, meta }, className = '', delegation, filt
|
||||
);
|
||||
}, [address, api, bestNumber, democracyLocks]);
|
||||
|
||||
useEffect((): void => {
|
||||
bestNumber && convictionLocks && setReferandaUnlock(
|
||||
(prev): ReferendaUnlockable => {
|
||||
const ids = convictionLocks
|
||||
.filter(({ endBlock }) => endBlock.gt(BN_ZERO) && bestNumber.gt(endBlock))
|
||||
.map(({ classId, refId }): [classId: BN, refId: BN] => [classId, refId]);
|
||||
|
||||
if (JSON.stringify(prev.ids) === JSON.stringify(ids)) {
|
||||
return prev;
|
||||
}
|
||||
|
||||
return {
|
||||
ids,
|
||||
referendaUnlockTx: createClearReferendaTx(api.api, address, ids)
|
||||
};
|
||||
}
|
||||
);
|
||||
}, [address, api, bestNumber, convictionLocks]);
|
||||
|
||||
const isVisible = useMemo(
|
||||
() => calcVisible(filter, accName, tags),
|
||||
[accName, filter, tags]
|
||||
@ -231,6 +280,14 @@ function Account ({ account: { address, meta }, className = '', delegation, filt
|
||||
[address, democracyUnlockTx, queueExtrinsic]
|
||||
);
|
||||
|
||||
const _clearReferendaLocks = useCallback(
|
||||
() => referendaUnlockTx && queueExtrinsic({
|
||||
accountId: address,
|
||||
extrinsic: referendaUnlockTx
|
||||
}),
|
||||
[address, referendaUnlockTx, queueExtrinsic]
|
||||
);
|
||||
|
||||
const _vestingVest = useCallback(
|
||||
() => vestingVestTx && queueExtrinsic({
|
||||
accountId: address,
|
||||
@ -276,6 +333,14 @@ function Account ({ account: { address, meta }, className = '', delegation, filt
|
||||
onClick={_clearDemocracyLocks}
|
||||
/>
|
||||
),
|
||||
isFunction(api.api.tx.convictionVoting?.unlock) && referendaUnlockTx && (
|
||||
<Menu.Item
|
||||
icon='broom'
|
||||
key='clearReferenda'
|
||||
label={t('Clear expired referenda locks')}
|
||||
onClick={_clearReferendaLocks}
|
||||
/>
|
||||
),
|
||||
isFunction(api.api.tx.vesting?.vest) && vestingVestTx && (
|
||||
<Menu.Item
|
||||
icon='unlock'
|
||||
@ -398,7 +463,7 @@ function Account ({ account: { address, meta }, className = '', delegation, filt
|
||||
/>
|
||||
])
|
||||
].filter((i) => i),
|
||||
[_clearDemocracyLocks, _showOnHardware, _vestingVest, api, delegation, democracyUnlockTx, genesisHash, identity, isDevelopment, isEditable, isEthereum, isExternal, isHardware, isInjected, isMultisig, multiInfos, onSetGenesisHash, proxy, recoveryInfo, t, toggleBackup, toggleDelegate, toggleDerive, toggleForget, toggleIdentityMain, toggleIdentitySub, toggleMultisig, togglePassword, toggleProxyOverview, toggleRecoverAccount, toggleRecoverSetup, toggleUndelegate, vestingVestTx]);
|
||||
[_clearDemocracyLocks, _clearReferendaLocks, _showOnHardware, _vestingVest, api, delegation, democracyUnlockTx, genesisHash, identity, isDevelopment, isEditable, isEthereum, isExternal, isHardware, isInjected, isMultisig, multiInfos, onSetGenesisHash, proxy, referendaUnlockTx, recoveryInfo, t, toggleBackup, toggleDelegate, toggleDerive, toggleForget, toggleIdentityMain, toggleIdentitySub, toggleMultisig, togglePassword, toggleProxyOverview, toggleRecoverAccount, toggleRecoverSetup, toggleUndelegate, vestingVestTx]);
|
||||
|
||||
if (!isVisible) {
|
||||
return null;
|
||||
@ -691,6 +756,7 @@ function Account ({ account: { address, meta }, className = '', delegation, filt
|
||||
<AddressInfo
|
||||
address={address}
|
||||
balancesAll={balancesAll}
|
||||
convictionLocks={convictionLocks}
|
||||
withBalance={BAL_OPTS_EXPANDED}
|
||||
withExtended={false}
|
||||
/>
|
||||
|
||||
@ -73,3 +73,11 @@ export interface TrackInfo {
|
||||
origin: Record<string, string> | Record<string, string>[];
|
||||
text?: string;
|
||||
}
|
||||
|
||||
export interface Lock {
|
||||
classId: BN;
|
||||
endBlock: BN;
|
||||
locked: string;
|
||||
refId: BN;
|
||||
total: BN;
|
||||
}
|
||||
|
||||
185
packages/page-referenda/src/useAccountLocks.ts
Normal file
185
packages/page-referenda/src/useAccountLocks.ts
Normal file
@ -0,0 +1,185 @@
|
||||
// Copyright 2017-2022 @polkadot/app-referenda authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { ApiPromise } from '@polkadot/api';
|
||||
import type { Option } from '@polkadot/types';
|
||||
import type { PalletConvictionVotingVoteCasting, PalletConvictionVotingVoteVoting, PalletReferendaReferendumInfoConvictionVotingTally } from '@polkadot/types/lookup';
|
||||
import type { BN } from '@polkadot/util';
|
||||
import type { Lock, PalletReferenda, PalletVote } from './types';
|
||||
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { createNamedHook, useApi, useCall } from '@polkadot/react-hooks';
|
||||
import { BN_MAX_INTEGER } from '@polkadot/util';
|
||||
|
||||
interface WithAbstain {
|
||||
asSplitAbstain: {
|
||||
abstain: BN;
|
||||
aye: BN;
|
||||
nay: BN;
|
||||
};
|
||||
isSplitAbstain: boolean;
|
||||
}
|
||||
|
||||
const OPT_CLASS = {
|
||||
transform: (locks: [BN, BN][]): BN[] =>
|
||||
locks.map(([classId]) => classId)
|
||||
};
|
||||
|
||||
const OPT_VOTES = {
|
||||
transform: ([[params], votes]: [[[string, BN][]], PalletConvictionVotingVoteVoting[]]): [classId: BN, refIds: BN[], casting: PalletConvictionVotingVoteCasting][] =>
|
||||
votes
|
||||
.map((v, index): null | [BN, BN[], PalletConvictionVotingVoteCasting] => {
|
||||
if (!v.isCasting) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const casting = v.asCasting;
|
||||
|
||||
return [
|
||||
params[index][1],
|
||||
casting.votes.map(([refId]) => refId),
|
||||
casting
|
||||
];
|
||||
})
|
||||
.filter((v): v is [BN, BN[], PalletConvictionVotingVoteCasting] => !!v),
|
||||
withParamsTransform: true
|
||||
};
|
||||
|
||||
const OPT_REFS = {
|
||||
transform: ([[params], optTally]: [[BN[]], Option<PalletReferendaReferendumInfoConvictionVotingTally>[]]): [BN, PalletReferendaReferendumInfoConvictionVotingTally][] =>
|
||||
optTally
|
||||
.map((v, index): null | [BN, PalletReferendaReferendumInfoConvictionVotingTally] =>
|
||||
v.isSome
|
||||
? [params[index], v.unwrap()]
|
||||
: null
|
||||
)
|
||||
.filter((v): v is [BN, PalletReferendaReferendumInfoConvictionVotingTally] => !!v),
|
||||
withParamsTransform: true
|
||||
};
|
||||
|
||||
function getVoteParams (accountId: string, lockClasses?: BN[]): [[accountId: string, classId: BN][]] | undefined {
|
||||
if (lockClasses) {
|
||||
return [lockClasses.map((classId) => [accountId, classId])];
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getRefParams (votes?: [classId: BN, refIds: BN[], casting: PalletConvictionVotingVoteCasting][]): [BN[]] | undefined {
|
||||
if (votes && votes.length) {
|
||||
const refIds = votes.reduce<BN[]>((all, [, refIds]) => all.concat(refIds), []);
|
||||
|
||||
if (refIds.length) {
|
||||
return [refIds];
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getLocks (api: ApiPromise, palletVote: PalletVote, votes: [classId: BN, refIds: BN[], casting: PalletConvictionVotingVoteCasting][], referenda: [BN, PalletReferendaReferendumInfoConvictionVotingTally][]): Lock[] {
|
||||
const lockPeriod = api.consts[palletVote].voteLockingPeriod as BN;
|
||||
const locks: Lock[] = [];
|
||||
|
||||
for (let i = 0; i < votes.length; i++) {
|
||||
const [classId,, casting] = votes[i];
|
||||
|
||||
for (let i = 0; i < casting.votes.length; i++) {
|
||||
const [refId, accountVote] = casting.votes[i];
|
||||
const refInfo = referenda.find(([id]) => id.eq(refId));
|
||||
|
||||
if (refInfo) {
|
||||
const [, tally] = refInfo;
|
||||
let total: BN | undefined;
|
||||
let endBlock: BN| undefined;
|
||||
let conviction = 0;
|
||||
let locked = 'None';
|
||||
|
||||
if (accountVote.isStandard) {
|
||||
const { balance, vote } = accountVote.asStandard;
|
||||
|
||||
total = balance;
|
||||
|
||||
if ((tally.isApproved && vote.isAye) || (tally.isRejected && vote.isNay)) {
|
||||
conviction = vote.conviction.index;
|
||||
locked = vote.conviction.type;
|
||||
}
|
||||
} else if (accountVote.isSplit) {
|
||||
const { aye, nay } = accountVote.asSplit;
|
||||
|
||||
total = aye.add(nay);
|
||||
} else if ((accountVote as unknown as WithAbstain).isSplitAbstain) {
|
||||
// FIXME Once we have updated the API with latest metadata, this won't be needed
|
||||
const { abstain, aye, nay } = (accountVote as unknown as WithAbstain).asSplitAbstain;
|
||||
|
||||
total = aye.add(nay).add(abstain);
|
||||
} else {
|
||||
console.error(`Unable to handle ${accountVote.type}`);
|
||||
}
|
||||
|
||||
if (tally.isOngoing) {
|
||||
endBlock = BN_MAX_INTEGER;
|
||||
} else if (tally.isKilled) {
|
||||
endBlock = tally.asKilled;
|
||||
} else if (tally.isCancelled || tally.isTimedOut) {
|
||||
endBlock = tally.isCancelled
|
||||
? tally.asCancelled[0]
|
||||
: tally.asTimedOut[0];
|
||||
} else if (tally.isApproved || tally.isRejected) {
|
||||
endBlock = lockPeriod
|
||||
.muln(conviction)
|
||||
.add(
|
||||
tally.isApproved
|
||||
? tally.asApproved[0]
|
||||
: tally.asRejected[0]
|
||||
);
|
||||
} else {
|
||||
console.error(`Unable to handle ${tally.type}`);
|
||||
}
|
||||
|
||||
if (total && endBlock) {
|
||||
locks.push({ classId, endBlock, locked, refId, total });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return locks;
|
||||
}
|
||||
|
||||
function useAccountLocksImpl (palletReferenda: PalletReferenda, palletVote: PalletVote, accountId: string): Lock[] | undefined {
|
||||
const { api } = useApi();
|
||||
|
||||
// retrieve the locks for the account (all classes) via the accountId
|
||||
const lockParams = useMemo(
|
||||
() => [accountId],
|
||||
[accountId]
|
||||
);
|
||||
|
||||
const lockClasses = useCall<BN[] | undefined>(lockParams && api.query[palletVote]?.classLocksFor, lockParams, OPT_CLASS);
|
||||
|
||||
// retrieve the specific votes casted over the classes & accountId
|
||||
const voteParams = useMemo(
|
||||
() => getVoteParams(accountId, lockClasses),
|
||||
[accountId, lockClasses]
|
||||
);
|
||||
|
||||
const votes = useCall<[BN, BN[], PalletConvictionVotingVoteCasting][] | undefined>(voteParams && api.query[palletVote]?.votingFor.multi, voteParams, OPT_VOTES);
|
||||
|
||||
// retrieve the referendums that were voted on
|
||||
const refParams = useMemo(
|
||||
() => getRefParams(votes),
|
||||
[votes]
|
||||
);
|
||||
|
||||
const referenda = useCall(refParams && api.query[palletReferenda]?.referendumInfoFor.multi, refParams, OPT_REFS);
|
||||
|
||||
// combine the referenda outcomes and the votes into locks
|
||||
return useMemo(
|
||||
() => votes && referenda && getLocks(api, palletVote, votes, referenda),
|
||||
[api, palletVote, referenda, votes]
|
||||
);
|
||||
}
|
||||
|
||||
export default createNamedHook('useAccountLocks', useAccountLocksImpl);
|
||||
@ -15,7 +15,7 @@ import { withCalls, withMulti } from '@polkadot/react-api/hoc';
|
||||
import { Expander, Icon, Tooltip } from '@polkadot/react-components';
|
||||
import { useBestNumber } from '@polkadot/react-hooks';
|
||||
import { BlockToTime, FormatBalance } from '@polkadot/react-query';
|
||||
import { BN_ZERO, bnMax, formatBalance, formatNumber, isObject } from '@polkadot/util';
|
||||
import { BN_MAX_INTEGER, BN_ZERO, bnMax, formatBalance, formatNumber, isObject } from '@polkadot/util';
|
||||
|
||||
import CryptoType from './CryptoType';
|
||||
import DemocracyLocks from './DemocracyLocks';
|
||||
@ -51,8 +51,8 @@ interface Props {
|
||||
address: string;
|
||||
balancesAll?: DeriveBalancesAll;
|
||||
children?: React.ReactNode;
|
||||
classLocksFor?: [BN, BN][];
|
||||
className?: string;
|
||||
convictionLocks?: RefLock[];
|
||||
democracyLocks?: DeriveDemocracyLock[];
|
||||
extraInfo?: [string, string][];
|
||||
stakingInfo?: DeriveStakingAccount;
|
||||
@ -65,6 +65,13 @@ interface Props {
|
||||
withLabel?: boolean;
|
||||
}
|
||||
|
||||
interface RefLock {
|
||||
endBlock: BN;
|
||||
locked: string;
|
||||
refId: BN;
|
||||
total: BN;
|
||||
}
|
||||
|
||||
const DEFAULT_BALANCES: BalanceActiveType = {
|
||||
available: true,
|
||||
bonded: true,
|
||||
@ -223,7 +230,7 @@ function renderValidatorPrefs ({ stakingInfo, withValidatorPrefs = false }: Prop
|
||||
);
|
||||
}
|
||||
|
||||
function createBalanceItems (formatIndex: number, lookup: Record<string, string>, t: TFunction, { address, balanceDisplay, balancesAll, bestNumber, classLocksFor, democracyLocks, isAllLocked, otherBonded, ownBonded, stakingInfo, votingOf, withBalanceToggle, withLabel }: { address: string; balanceDisplay: BalanceActiveType; balancesAll?: DeriveBalancesAll | DeriveBalancesAccountData; bestNumber: BlockNumber; classLocksFor?: [BN, BN][]; democracyLocks?: DeriveDemocracyLock[]; isAllLocked: boolean; otherBonded: BN[]; ownBonded: BN; stakingInfo?: DeriveStakingAccount; votingOf?: Voting; withBalanceToggle: boolean, withLabel: boolean }): React.ReactNode {
|
||||
function createBalanceItems (formatIndex: number, lookup: Record<string, string>, t: TFunction, { address, balanceDisplay, balancesAll, bestNumber, convictionLocks, democracyLocks, isAllLocked, otherBonded, ownBonded, stakingInfo, votingOf, withBalanceToggle, withLabel }: { address: string; balanceDisplay: BalanceActiveType; balancesAll?: DeriveBalancesAll | DeriveBalancesAccountData; bestNumber: BlockNumber; convictionLocks?: RefLock[]; democracyLocks?: DeriveDemocracyLock[]; isAllLocked: boolean; otherBonded: BN[]; ownBonded: BN; stakingInfo?: DeriveStakingAccount; votingOf?: Voting; withBalanceToggle: boolean, withLabel: boolean }): React.ReactNode {
|
||||
const allItems: React.ReactNode[] = [];
|
||||
const deriveBalances = balancesAll as DeriveBalancesAll;
|
||||
|
||||
@ -432,15 +439,41 @@ function createBalanceItems (formatIndex: number, lookup: Record<string, string>
|
||||
);
|
||||
}
|
||||
|
||||
if (classLocksFor && (classLocksFor.length !== 0)) {
|
||||
const max = classLocksFor.reduce((max, [, value]) => bnMax(max, value), BN_ZERO);
|
||||
if (convictionLocks && convictionLocks.length) {
|
||||
const max = convictionLocks.reduce((max, { total }) => bnMax(max, total), BN_ZERO);
|
||||
|
||||
allItems.push(
|
||||
<React.Fragment key={9}>
|
||||
<Label label={t<string>('referenda')} />
|
||||
<FormatBalance
|
||||
className='result'
|
||||
labelPost={<IconVoid />}
|
||||
labelPost={
|
||||
<>
|
||||
<Icon
|
||||
icon='clock'
|
||||
tooltip={`${address}-conviction-locks-trigger`}
|
||||
/>
|
||||
<Tooltip
|
||||
text={convictionLocks.map(({ endBlock, locked, refId, total }, index): React.ReactNode => (
|
||||
<div key={index}>
|
||||
<div className='nowrap'>#{refId.toString()} {formatBalance(total, { forceUnit: '-' })} {locked}</div>
|
||||
<div className='faded nowrap'>{
|
||||
endBlock.eq(BN_MAX_INTEGER)
|
||||
? t('ongoing referendum')
|
||||
: bestNumber.gte(endBlock)
|
||||
? t('lock expired')
|
||||
: <>{formatNumber(endBlock.sub(bestNumber))} {t('blocks')},
|
||||
<BlockToTime
|
||||
isInline
|
||||
value={endBlock.sub(bestNumber)}
|
||||
/></>
|
||||
}</div>
|
||||
</div>
|
||||
))}
|
||||
trigger={`${address}-conviction-locks-trigger`}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
value={max}
|
||||
/>
|
||||
</React.Fragment>
|
||||
@ -477,7 +510,7 @@ function createBalanceItems (formatIndex: number, lookup: Record<string, string>
|
||||
}
|
||||
|
||||
function renderBalances (props: Props, lookup: Record<string, string>, bestNumber: BlockNumber | undefined, t: TFunction): React.ReactNode[] {
|
||||
const { address, balancesAll, classLocksFor, democracyLocks, stakingInfo, votingOf, withBalance = true, withBalanceToggle = false, withLabel = false } = props;
|
||||
const { address, balancesAll, convictionLocks, democracyLocks, stakingInfo, votingOf, withBalance = true, withBalanceToggle = false, withLabel = false } = props;
|
||||
const balanceDisplay = withBalance === true
|
||||
? DEFAULT_BALANCES
|
||||
: withBalance || false;
|
||||
@ -488,7 +521,7 @@ function renderBalances (props: Props, lookup: Record<string, string>, bestNumbe
|
||||
|
||||
const [ownBonded, otherBonded] = calcBonded(stakingInfo, balanceDisplay.bonded);
|
||||
const isAllLocked = !!balancesAll && balancesAll.lockedBreakdown.some(({ amount }): boolean => amount?.isMax());
|
||||
const baseOpts = { address, balanceDisplay, bestNumber, classLocksFor, democracyLocks, isAllLocked, otherBonded, ownBonded, votingOf, withBalanceToggle, withLabel };
|
||||
const baseOpts = { address, balanceDisplay, bestNumber, convictionLocks, democracyLocks, isAllLocked, otherBonded, ownBonded, votingOf, withBalanceToggle, withLabel };
|
||||
const items = [createBalanceItems(0, lookup, t, { ...baseOpts, balancesAll, stakingInfo })];
|
||||
|
||||
withBalanceToggle && balancesAll?.additional.length && balancesAll.additional.forEach((balancesAll, index): void => {
|
||||
@ -563,6 +596,14 @@ export default withMulti(
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.nowrap {
|
||||
white-space: nowrap;
|
||||
|
||||
.ui--FormatBalance {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
.column {
|
||||
max-width: 260px;
|
||||
&.column--expander {
|
||||
@ -644,11 +685,6 @@ export default withMulti(
|
||||
paramName: 'address',
|
||||
propName: 'votingOf',
|
||||
skipIf: skipStakingIf
|
||||
}],
|
||||
['query.convictionVoting.classLocksFor', {
|
||||
paramName: 'address',
|
||||
propName: 'classLocksFor',
|
||||
skipIf: skipStakingIf
|
||||
}]
|
||||
)
|
||||
);
|
||||
|
||||
@ -26,7 +26,7 @@ function BlockToTime ({ api, children, className = '', isInline, label, value }:
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`${className}${isInline ? ' isInline' : ''}`}>
|
||||
<div className={`.ui--BlockToTime ${className}${isInline ? ' isInline' : ''}`}>
|
||||
{label || ''}{text.split(' ').map((v, index) =>
|
||||
<span
|
||||
className={index % 2 ? 'timeUnits' : undefined}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user