From dc7b4cb449018f7e494ba8e8112007c047c35036 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Mon, 8 Jun 2020 11:25:21 +0200 Subject: [PATCH] Multisig final detection (#2900) --- .../page-staking/src/Payouts/PayButton.tsx | 9 ++++-- packages/react-api/src/Api.tsx | 6 ++-- packages/react-signer/src/Modal.tsx | 32 +++++++++++++++++-- 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/packages/page-staking/src/Payouts/PayButton.tsx b/packages/page-staking/src/Payouts/PayButton.tsx index 903bf5da29..14b3fc901a 100644 --- a/packages/page-staking/src/Payouts/PayButton.tsx +++ b/packages/page-staking/src/Payouts/PayButton.tsx @@ -12,6 +12,8 @@ import { useApi, useToggle } from '@polkadot/react-hooks'; import { useTranslation } from '../translate'; +const MAX_BATCH_SIZE = 40; + interface Props { isAll?: boolean; isDisabled?: boolean; @@ -29,7 +31,7 @@ function createExtrinsic (api: ApiPromise, payout: PayoutValidator | PayoutValid calls.concat( ...eras.map(({ era }) => api.tx.staking.payoutStakers(validatorId, era)) ), [] - ).filter((_, index) => index < 40) + ).filter((_, index) => index < MAX_BATCH_SIZE) ); } @@ -38,7 +40,9 @@ function createExtrinsic (api: ApiPromise, payout: PayoutValidator | PayoutValid return eras.length === 1 ? api.tx.staking.payoutStakers(validatorId, eras[0].era) : api.tx.utility.batch( - eras.map(({ era }) => api.tx.staking.payoutStakers(validatorId, era)) + eras + .map(({ era }) => api.tx.staking.payoutStakers(validatorId, era)) + .filter((_, index) => index < MAX_BATCH_SIZE) ); } @@ -105,6 +109,7 @@ function PayButton ({ isAll, isDisabled, payout }: Props): React.ReactElement

{t('All the listed validators and all their nominators will receive their rewards.')}

+

{t('The UI puts a limit of 40 payouts at a time, where each payout is a single validator for a single era.')}

diff --git a/packages/react-api/src/Api.tsx b/packages/react-api/src/Api.tsx index cbce6a83dd..6001b11f5b 100644 --- a/packages/react-api/src/Api.tsx +++ b/packages/react-api/src/Api.tsx @@ -37,6 +37,7 @@ interface InjectedAccountExt { meta: { name: string; source: string; + whenCreated: number; }; } @@ -73,11 +74,12 @@ async function retrieve (api: ApiPromise): Promise { api.rpc.system.version(), injectedPromise .then(() => web3Accounts()) - .then((accounts) => accounts.map(({ address, meta }): InjectedAccountExt => ({ + .then((accounts) => accounts.map(({ address, meta }, whenCreated): InjectedAccountExt => ({ address, meta: { ...meta, - name: `${meta.name || 'unknown'} (${meta.source === 'polkadot-js' ? 'extension' : meta.source})` + name: `${meta.name || 'unknown'} (${meta.source === 'polkadot-js' ? 'extension' : meta.source})`, + whenCreated } }))) .catch((error): InjectedAccountExt[] => { diff --git a/packages/react-signer/src/Modal.tsx b/packages/react-signer/src/Modal.tsx index 7e558dac46..4bb41f7f8f 100644 --- a/packages/react-signer/src/Modal.tsx +++ b/packages/react-signer/src/Modal.tsx @@ -170,14 +170,24 @@ class Signer extends React.PureComponent { } public async componentDidUpdate (): Promise { - const { accountNonce, currentItem, isSubmit } = this.state; + const { accountNonce, currentItem, isSendable, isSubmit } = this.state; if (currentItem && currentItem.status === 'queued' && !(currentItem.extrinsic || currentItem.payload)) { return this.sendRpc(currentItem); } - if (!isSubmit && currentItem?.accountId && accountNonce == null) { - this.updateNonce().catch(console.error); + if (currentItem?.accountId) { + if (!isSubmit && accountNonce == null) { + this.updateNonce().catch(console.error); + } + + if (isSendable) { + const { isMultisig } = extractExternal(currentItem.accountId); + + if (isMultisig) { + this.checkMultisig().catch(console.error); + } + } } } @@ -617,6 +627,22 @@ class Signer extends React.PureComponent { this.setState({ accountNonce, nonce: accountNonce }); }; + private checkMultisig = async (): Promise => { + const { api } = this.props; + const { currentItem } = this.state; + + if (currentItem?.accountId && currentItem?.extrinsic) { + const multiModule = api.tx.multisig ? 'multisig' : 'utility'; + const { threshold } = extractExternal(currentItem.accountId); + const optMulti = await api.query[multiModule].multisigs>(currentItem.accountId, currentItem.extrinsic.method.hash); + const multi = optMulti.unwrapOr(null); + + if (multi && ((multi.approvals.length + 1) >= threshold)) { + this.setState({ multiCall: true }); + } + } + } + private signQrPayload = (payload: SignerPayloadJSON): Promise => { return new Promise((resolve, reject): void => { // limit size of the transaction