Tips & old-payouts via useBatchTx (#5056)

This commit is contained in:
Jaco Greeff 2021-04-12 14:06:24 +03:00 committed by GitHub
parent fe2e8060eb
commit ecd6c5e53f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 32 additions and 43 deletions

View File

@ -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')}
/>
)}

View File

@ -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>

View File

@ -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>