Tips & old-payouts via useBatchTx (#5056)
This commit is contained in:
parent
fe2e8060eb
commit
ecd6c5e53f
@ -10,7 +10,7 @@ import React, { useEffect, useState } from 'react';
|
||||
|
||||
import { ApiPromise } from '@polkadot/api';
|
||||
import { AddressSmall, TxButton } from '@polkadot/react-components';
|
||||
import { useApi, useCall } from '@polkadot/react-hooks';
|
||||
import { useApi, useCall, useTxBatch } from '@polkadot/react-hooks';
|
||||
import { BlockToTime, FormatBalance } from '@polkadot/react-query';
|
||||
|
||||
import { useTranslation } from '../translate';
|
||||
@ -29,24 +29,22 @@ interface EraInfo {
|
||||
oldestEra?: BN;
|
||||
}
|
||||
|
||||
function createPrevPayoutType (api: ApiPromise, { era, isValidator, nominating }: DeriveStakerReward): SubmittableExtrinsic<'promise'> {
|
||||
return isValidator
|
||||
? api.tx.staking.payoutValidator(era)
|
||||
: api.tx.staking.payoutNominator(era, nominating.map(({ validatorId, validatorIndex }): [string, number] =>
|
||||
[validatorId, validatorIndex]
|
||||
));
|
||||
}
|
||||
|
||||
function createPrevPayout (api: ApiPromise, payoutRewards: DeriveStakerReward[]): SubmittableExtrinsic<'promise'> {
|
||||
return payoutRewards.length === 1
|
||||
? createPrevPayoutType(api, payoutRewards[0])
|
||||
: api.tx.utility.batch(payoutRewards.map((reward) => createPrevPayoutType(api, reward)));
|
||||
// TODO This is pre Substrate 2.0, remove
|
||||
function createPrevPayouts (api: ApiPromise, payoutRewards: DeriveStakerReward[]): SubmittableExtrinsic<'promise'>[] {
|
||||
return payoutRewards.map(({ era, isValidator, nominating }) =>
|
||||
isValidator
|
||||
? api.tx.staking.payoutValidator(era)
|
||||
: api.tx.staking.payoutNominator(era, nominating.map(({ validatorId, validatorIndex }): [string, number] =>
|
||||
[validatorId, validatorIndex]
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
function Stash ({ className = '', isDisabled, payout: { available, rewards, stashId }, stakerPayoutsAfter }: Props): React.ReactElement<Props> | null {
|
||||
const { t } = useTranslation();
|
||||
const { api } = useApi();
|
||||
const [extrinsic, setExtrinsic] = useState<SubmittableExtrinsic<'promise'> | null>(null);
|
||||
const [payoutTxs, setPayoutTxs] = useState<SubmittableExtrinsic<'promise'>[]>([]);
|
||||
const batchTx = useTxBatch(payoutTxs);
|
||||
const [{ eraStr, oldestEra }, setEraInfo] = useState<EraInfo>({ eraStr: '' });
|
||||
const eraBlocks = useEraBlocks(oldestEra);
|
||||
const stakingAccount = useCall<DeriveStakingAccount>(api.derive.staking.account, [stashId]);
|
||||
@ -59,15 +57,9 @@ function Stash ({ className = '', isDisabled, payout: { available, rewards, stas
|
||||
}, [rewards]);
|
||||
|
||||
useEffect((): void => {
|
||||
if (rewards) {
|
||||
const available = rewards.filter(({ era }) => era.lt(stakerPayoutsAfter));
|
||||
|
||||
setExtrinsic(
|
||||
api.tx.utility && available.length
|
||||
? createPrevPayout(api, available)
|
||||
: null
|
||||
);
|
||||
}
|
||||
rewards && setPayoutTxs(
|
||||
createPrevPayouts(api, rewards.filter(({ era }) => era.lt(stakerPayoutsAfter)))
|
||||
);
|
||||
}, [api, rewards, stakerPayoutsAfter]);
|
||||
|
||||
if (available.isZero()) {
|
||||
@ -91,12 +83,12 @@ function Stash ({ className = '', isDisabled, payout: { available, rewards, stas
|
||||
className='button'
|
||||
colSpan={3}
|
||||
>
|
||||
{extrinsic && stakingAccount && (
|
||||
{batchTx && stakingAccount && (
|
||||
<TxButton
|
||||
accountId={stakingAccount.controllerId}
|
||||
extrinsic={extrinsic}
|
||||
extrinsic={batchTx}
|
||||
icon='credit-card'
|
||||
isDisabled={!extrinsic || isDisabled}
|
||||
isDisabled={!batchTx || isDisabled}
|
||||
label={t<string>('Payout')}
|
||||
/>
|
||||
)}
|
||||
|
||||
@ -159,7 +159,6 @@ function Payouts ({ className = '', isInElection, ownValidators }: Props): React
|
||||
const eraLength = useCall<BN>(api.derive.session.eraLength);
|
||||
const historyDepth = useCall<BN>(api.query.staking.historyDepth);
|
||||
const stakerPayoutsAfter = useStakerPayouts();
|
||||
const isDisabled = isInElection || !isFunction(api.tx.utility?.batch);
|
||||
|
||||
const eraSelection = useMemo(
|
||||
() => getOptions(api, eraLength, historyDepth, t),
|
||||
@ -205,6 +204,7 @@ function Payouts ({ className = '', isInElection, ownValidators }: Props): React
|
||||
), [stashTotal]);
|
||||
|
||||
const hasPayouts = isFunction(api.tx.staking.payoutStakers);
|
||||
const isDisabled = isInElection || !isFunction(api.tx.utility?.batch);
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
@ -222,7 +222,7 @@ function Payouts ({ className = '', isInElection, ownValidators }: Props): React
|
||||
/>
|
||||
<PayButton
|
||||
isAll
|
||||
isDisabled={isDisabled}
|
||||
isDisabled={isInElection}
|
||||
payout={validators}
|
||||
/>
|
||||
</Button.Group>
|
||||
|
||||
@ -7,7 +7,7 @@ import BN from 'bn.js';
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
|
||||
import { Button, TxButton } from '@polkadot/react-components';
|
||||
import { useAccounts, useApi } from '@polkadot/react-hooks';
|
||||
import { useAccounts, useApi, useTxBatch } from '@polkadot/react-hooks';
|
||||
|
||||
import { useTranslation } from '../translate';
|
||||
import TipCreate from './TipCreate';
|
||||
@ -22,14 +22,17 @@ interface Props {
|
||||
|
||||
interface QuickTipsState {
|
||||
quickTips: Record<string, BN | null>;
|
||||
quickTx: SubmittableExtrinsic<'promise'> | null;
|
||||
quickTxs: SubmittableExtrinsic<'promise'>[];
|
||||
}
|
||||
|
||||
const DEFAULT_TIPS = { quickTips: {}, quickTxs: [] };
|
||||
|
||||
function TipsEntry ({ className, hashes, isMember, members }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const { allAccounts } = useAccounts();
|
||||
const { api } = useApi();
|
||||
const [{ quickTx }, setQuickTips] = useState<QuickTipsState>({ quickTips: {}, quickTx: null });
|
||||
const [{ quickTxs }, setQuickTips] = useState<QuickTipsState>(DEFAULT_TIPS);
|
||||
const batchTxs = useTxBatch(quickTxs);
|
||||
|
||||
const defaultId = useMemo(
|
||||
() => members.find((memberId) => allAccounts.includes(memberId)) || null,
|
||||
@ -40,18 +43,12 @@ function TipsEntry ({ className, hashes, isMember, members }: Props): React.Reac
|
||||
(hash: string, isSelected: boolean, value: BN) => setQuickTips(({ quickTips }): QuickTipsState => {
|
||||
quickTips[hash] = isSelected ? value : null;
|
||||
|
||||
const available = Object
|
||||
.entries(quickTips)
|
||||
.map(([hash, value]) => value && (api.tx.tips || api.tx.treasury).tip(hash, value))
|
||||
.filter((value): value is SubmittableExtrinsic<'promise'> => !!value);
|
||||
|
||||
return {
|
||||
quickTips,
|
||||
quickTx: available.length
|
||||
? available.length === 1
|
||||
? available[0]
|
||||
: api.tx.utility.batch(available)
|
||||
: null
|
||||
quickTxs: Object
|
||||
.entries(quickTips)
|
||||
.map(([hash, value]) => value && (api.tx.tips || api.tx.treasury).tip(hash, value))
|
||||
.filter((value): value is SubmittableExtrinsic<'promise'> => !!value)
|
||||
};
|
||||
}),
|
||||
[api]
|
||||
@ -63,9 +60,9 @@ function TipsEntry ({ className, hashes, isMember, members }: Props): React.Reac
|
||||
<TipCreate members={members} />
|
||||
<TxButton
|
||||
accountId={defaultId}
|
||||
extrinsic={quickTx}
|
||||
extrinsic={batchTxs}
|
||||
icon='fighter-jet'
|
||||
isDisabled={!isMember || !quickTx}
|
||||
isDisabled={!isMember || !batchTxs}
|
||||
label={t<string>('Median tip selected')}
|
||||
/>
|
||||
</Button.Group>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user