Submit multiple txs via Payout all (#3756)
* Submit multiple txs via Payout all * Single onstart event
This commit is contained in:
parent
eab4a7452d
commit
42e06de3c9
@ -25,37 +25,44 @@ interface SinglePayout {
|
||||
validatorId: string;
|
||||
}
|
||||
|
||||
function createExtrinsic (api: ApiPromise, payout: PayoutValidator | PayoutValidator[], maxPayouts: number): SubmittableExtrinsic<'promise'> | null {
|
||||
function createBatches (api: ApiPromise, maxPayouts: number, payouts: SinglePayout[]): SubmittableExtrinsic<'promise'>[] {
|
||||
return payouts
|
||||
.sort((a, b) => a.era.cmp(b.era))
|
||||
.reduce((batches: SubmittableExtrinsic<'promise'>[][], { era, validatorId }): SubmittableExtrinsic<'promise'>[][] => {
|
||||
const tx = api.tx.staking.payoutStakers(validatorId, era);
|
||||
const batch = batches[batches.length - 1];
|
||||
|
||||
if (batch.length >= maxPayouts) {
|
||||
batches.push([tx]);
|
||||
} else {
|
||||
batch.push(tx);
|
||||
}
|
||||
|
||||
return batches;
|
||||
}, [[]])
|
||||
.map((batch) => api.tx.utility.batch(batch));
|
||||
}
|
||||
|
||||
function createExtrinsics (api: ApiPromise, payout: PayoutValidator | PayoutValidator[], maxPayouts: number): SubmittableExtrinsic<'promise'>[] | null {
|
||||
if (Array.isArray(payout)) {
|
||||
if (payout.length === 1) {
|
||||
return createExtrinsic(api, payout[0], maxPayouts);
|
||||
return createExtrinsics(api, payout[0], maxPayouts);
|
||||
}
|
||||
|
||||
return api.tx.utility.batch(
|
||||
payout
|
||||
.reduce((payouts: SinglePayout[], { eras, validatorId }): SinglePayout[] => {
|
||||
eras.forEach(({ era }): void => {
|
||||
payouts.push({ era, validatorId });
|
||||
});
|
||||
return createBatches(api, maxPayouts, payout.reduce((payouts: SinglePayout[], { eras, validatorId }): SinglePayout[] => {
|
||||
eras.forEach(({ era }): void => {
|
||||
payouts.push({ era, validatorId });
|
||||
});
|
||||
|
||||
return payouts;
|
||||
}, [])
|
||||
.sort((a, b) => a.era.cmp(b.era))
|
||||
.filter((_, index) => index < maxPayouts)
|
||||
.map(({ era, validatorId }) => api.tx.staking.payoutStakers(validatorId, era))
|
||||
);
|
||||
return payouts;
|
||||
}, []));
|
||||
}
|
||||
|
||||
const { eras, validatorId } = payout;
|
||||
|
||||
return eras.length === 1
|
||||
? api.tx.staking.payoutStakers(validatorId, eras[0].era)
|
||||
: api.tx.utility.batch(
|
||||
eras
|
||||
.sort((a, b) => a.era.cmp(b.era))
|
||||
.filter((_, index) => index < maxPayouts)
|
||||
.map(({ era }) => api.tx.staking.payoutStakers(validatorId, era))
|
||||
);
|
||||
? [api.tx.staking.payoutStakers(validatorId, eras[0].era)]
|
||||
: createBatches(api, maxPayouts, eras.map((era): SinglePayout => ({ era: era.era, validatorId })));
|
||||
}
|
||||
|
||||
function PayButton ({ className, isAll, isDisabled, payout }: Props): React.ReactElement<Props> {
|
||||
@ -64,7 +71,7 @@ function PayButton ({ className, isAll, isDisabled, payout }: Props): React.Reac
|
||||
const { allAccounts } = useAccounts();
|
||||
const [isVisible, togglePayout] = useToggle();
|
||||
const [accountId, setAccount] = useState<string | null>(null);
|
||||
const [extrinsic, setExtrinsic] = useState<SubmittableExtrinsic<'promise'> | null>(null);
|
||||
const [extrinsics, setExtrinsics] = useState<SubmittableExtrinsic<'promise'>[] | null>(null);
|
||||
const [maxPayouts, setMaxPayouts] = useState(0);
|
||||
|
||||
useEffect((): void => {
|
||||
@ -90,8 +97,8 @@ function PayButton ({ className, isAll, isDisabled, payout }: Props): React.Reac
|
||||
}, [allAccounts, api, payout]);
|
||||
|
||||
useEffect((): void => {
|
||||
api.tx.utility && payout && setExtrinsic(
|
||||
() => createExtrinsic(api, payout, maxPayouts)
|
||||
api.tx.utility && payout && setExtrinsics(
|
||||
() => createExtrinsics(api, payout, maxPayouts)
|
||||
);
|
||||
}, [api, maxPayouts, payout]);
|
||||
|
||||
@ -154,9 +161,9 @@ function PayButton ({ className, isAll, isDisabled, payout }: Props): React.Reac
|
||||
<Modal.Actions onCancel={togglePayout}>
|
||||
<TxButton
|
||||
accountId={accountId}
|
||||
extrinsic={extrinsic}
|
||||
extrinsic={extrinsics}
|
||||
icon='credit-card'
|
||||
isDisabled={!extrinsic || !accountId}
|
||||
isDisabled={!extrinsics || !extrinsics.length || !accountId}
|
||||
label={t<string>('Payout')}
|
||||
onStart={togglePayout}
|
||||
/>
|
||||
|
||||
@ -4,9 +4,9 @@
|
||||
import { SubmittableExtrinsic } from '@polkadot/api/types';
|
||||
import { TxButtonProps as Props } from './types';
|
||||
|
||||
import React, { useCallback, useContext } from 'react';
|
||||
import React, { useCallback, useContext, useEffect, useState } from 'react';
|
||||
import { SubmittableResult } from '@polkadot/api';
|
||||
import { useApi, useToggle } from '@polkadot/react-hooks';
|
||||
import { useApi } from '@polkadot/react-hooks';
|
||||
import { assert, isFunction } from '@polkadot/util';
|
||||
|
||||
import Button from './Button';
|
||||
@ -17,9 +17,14 @@ function TxButton ({ accountId, className = '', extrinsic: propsExtrinsic, icon,
|
||||
const { t } = useTranslation();
|
||||
const { api } = useApi();
|
||||
const { queueExtrinsic } = useContext(StatusContext);
|
||||
const [isSending, , setIsSending] = useToggle(false);
|
||||
const [isSending, setIsSending] = useState(false);
|
||||
const [isStarted, setIsStarted] = useState(false);
|
||||
const needsAccount = !isUnsigned && !accountId;
|
||||
|
||||
useEffect((): void => {
|
||||
(isStarted && onStart) && onStart();
|
||||
}, [isStarted, onStart]);
|
||||
|
||||
const _onFailed = useCallback(
|
||||
(result: SubmittableResult | null): void => {
|
||||
setIsSending(false);
|
||||
@ -38,43 +43,54 @@ function TxButton ({ accountId, className = '', extrinsic: propsExtrinsic, icon,
|
||||
[onSuccess, setIsSending]
|
||||
);
|
||||
|
||||
const _onStart = useCallback(
|
||||
() => setIsStarted(true),
|
||||
[setIsStarted]
|
||||
);
|
||||
|
||||
const _onSend = useCallback(
|
||||
(): void => {
|
||||
let extrinsic: SubmittableExtrinsic<'promise'>;
|
||||
let extrinsics: SubmittableExtrinsic<'promise'>[];
|
||||
|
||||
if (propsExtrinsic) {
|
||||
extrinsic = propsExtrinsic;
|
||||
extrinsics = Array.isArray(propsExtrinsic)
|
||||
? propsExtrinsic
|
||||
: [propsExtrinsic];
|
||||
} else {
|
||||
const [section, method] = (tx || '').split('.');
|
||||
|
||||
assert(api.tx[section] && api.tx[section][method], `Unable to find api.tx.${section}.${method}`);
|
||||
|
||||
extrinsic = api.tx[section][method](...(
|
||||
isFunction(params)
|
||||
? params()
|
||||
: (params || [])
|
||||
));
|
||||
extrinsics = [
|
||||
api.tx[section][method](...(
|
||||
isFunction(params)
|
||||
? params()
|
||||
: (params || [])
|
||||
))
|
||||
];
|
||||
}
|
||||
|
||||
assert(extrinsic, 'Expected generated extrinsic passed to TxButton');
|
||||
assert(extrinsics?.length, 'Expected generated extrinsic passed to TxButton');
|
||||
|
||||
if (withSpinner) {
|
||||
setIsSending(true);
|
||||
}
|
||||
|
||||
queueExtrinsic({
|
||||
accountId: accountId && accountId.toString(),
|
||||
extrinsic,
|
||||
isUnsigned,
|
||||
txFailedCb: withSpinner ? _onFailed : onFailed,
|
||||
txStartCb: onStart,
|
||||
txSuccessCb: withSpinner ? _onSuccess : onSuccess,
|
||||
txUpdateCb: onUpdate
|
||||
extrinsics.forEach((extrinsic): void => {
|
||||
queueExtrinsic({
|
||||
accountId: accountId && accountId.toString(),
|
||||
extrinsic,
|
||||
isUnsigned,
|
||||
txFailedCb: withSpinner ? _onFailed : onFailed,
|
||||
txStartCb: _onStart,
|
||||
txSuccessCb: withSpinner ? _onSuccess : onSuccess,
|
||||
txUpdateCb: onUpdate
|
||||
});
|
||||
});
|
||||
|
||||
onClick && onClick();
|
||||
},
|
||||
[_onFailed, _onSuccess, accountId, api.tx, isUnsigned, onClick, onFailed, onStart, onSuccess, onUpdate, params, propsExtrinsic, queueExtrinsic, setIsSending, tx, withSpinner]
|
||||
[_onFailed, _onStart, _onSuccess, accountId, api.tx, isUnsigned, onClick, onFailed, onSuccess, onUpdate, params, propsExtrinsic, queueExtrinsic, setIsSending, tx, withSpinner]
|
||||
);
|
||||
|
||||
if (onSendRef) {
|
||||
|
||||
@ -39,7 +39,7 @@ export interface TxTriggerProps {
|
||||
export type TxTrigger = React.ComponentType<TxTriggerProps>;
|
||||
|
||||
export interface TxProps {
|
||||
extrinsic?: SubmittableExtrinsic | null;
|
||||
extrinsic?: SubmittableExtrinsic | SubmittableExtrinsic[] | null;
|
||||
tx?: string;
|
||||
params?: any[] | ConstructTxFn;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user