Fix actual exec (#3842)

* Fix actual exec

* Adjust

* Remove (now unused) api

* Cleanup state on unmounted

* Update

* Use isPayable flag
This commit is contained in:
Jaco Greeff 2020-10-10 21:43:20 +02:00 committed by GitHub
parent 031a38acde
commit 9d51e0462a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 39 additions and 34 deletions

View File

@ -10,8 +10,7 @@ import React, { useCallback, useState, useEffect, useMemo } from 'react';
import styled from 'styled-components';
import { Button, Dropdown, IconLink, InputAddress, InputBalance, Modal, TxButton } from '@polkadot/react-components';
import { PromiseContract as ApiContract } from '@polkadot/api-contract';
import { useAccountId, useFormField, useToggle } from '@polkadot/react-hooks';
import { createValue } from '@polkadot/react-params/values';
import { useAccountId, useFormField } from '@polkadot/react-hooks';
import { BN_ZERO } from '@polkadot/util';
import { InputMegaGas, Params } from '../shared';
@ -34,23 +33,24 @@ function Call ({ callContract, callMessageIndex, className = '', onChangeCallCon
const callMessage = callContract.abi.messages[callMessageIndex];
const [accountId, setAccountId] = useAccountId();
const [endowment, isEndowmentValid, setEndowment] = useFormField<BN>(BN_ZERO);
const [isBusy, , setIsBusy] = useToggle();
const [outcomes, setOutcomes] = useState<ContractCallOutcome[]>([]);
const [execTx, setExecTx] = useState<SubmittableExtrinsic<'promise'> | null>(null);
const [params, setParams] = useState<any[]>(callMessage ? callMessage.args.map(({ type }) => createValue({ type })) : []);
const [params, setParams] = useState<any[]>([]);
const useWeightHook = useWeight();
const { isValid: isWeightValid, weight } = useWeightHook;
useEffect((): void => {
const callMessage = callContract.abi.messages[callMessageIndex];
setParams(callMessage ? callMessage.args.map(({ type }) => createValue({ type })) : []);
setParams([]);
}, [callContract, callMessageIndex]);
useEffect((): void => {
endowment && callContract.hasRpcContractsCall && callMessage.isMutating && setExecTx(
() => callContract.exec(callMessage, endowment, weight, ...params)
);
endowment && callMessage.isMutating && setExecTx((): SubmittableExtrinsic<'promise'> | null => {
try {
return callContract.exec(callMessage, callMessage.isPayable ? endowment : 0, weight, ...params);
} catch (error) {
return null;
}
});
}, [accountId, callContract, callMessage, endowment, weight, params]);
const _onChangeCallMessageIndexString = useCallback(
@ -104,7 +104,6 @@ function Call ({ callContract, callMessageIndex, className = '', onChangeCallCon
<InputAddress
defaultValue={accountId}
help={t<string>('Specify the user account to use for this contract call. And fees will be deducted from this account.')}
isDisabled={isBusy}
label={t<string>('call from account')}
onChange={setAccountId}
type='account'
@ -112,7 +111,6 @@ function Call ({ callContract, callMessageIndex, className = '', onChangeCallCon
/>
<InputAddress
help={t<string>('A deployed contract that has either been deployed or attached. The address and ABI are used to construct the parameters.')}
isDisabled={isBusy}
label={t<string>('contract to use')}
onChange={onChangeCallContractAddress}
type='contract'
@ -123,7 +121,6 @@ function Call ({ callContract, callMessageIndex, className = '', onChangeCallCon
<Dropdown
defaultValue={`${callMessageIndex}`}
help={t<string>('The message to send to this contract. Parameters are adjusted based on the ABI provided.')}
isDisabled={isBusy}
isError={callMessage === null}
label={t<string>('message to send')}
onChange={_onChangeCallMessageIndexString}
@ -131,7 +128,6 @@ function Call ({ callContract, callMessageIndex, className = '', onChangeCallCon
value={`${callMessageIndex}`}
/>
<Params
isDisabled={isBusy}
onChange={setParams}
params={
callMessage
@ -141,10 +137,9 @@ function Call ({ callContract, callMessageIndex, className = '', onChangeCallCon
/>
</>
)}
{!isViaRpc && (
{!isViaRpc && callMessage.isPayable && (
<InputBalance
help={t<string>('The allotted value for this contract, i.e. the amount transferred to the contract as part of this call.')}
isDisabled={isBusy}
isError={!isEndowmentValid}
isZeroable
label={t<string>('value')}
@ -197,9 +192,6 @@ function Call ({ callContract, callMessageIndex, className = '', onChangeCallCon
icon='sign-in-alt'
isDisabled={!isValid}
label={t('Execute')}
onClick={(): void => setIsBusy(true)}
onFailed={(): void => setIsBusy(false)}
onSuccess={(): void => setIsBusy(false)}
withSpinner
/>
)

View File

@ -6,7 +6,7 @@ import { TxButtonProps as Props } from './types';
import React, { useCallback, useContext, useEffect, useState } from 'react';
import { SubmittableResult } from '@polkadot/api';
import { useApi } from '@polkadot/react-hooks';
import { useApi, useIsMountedRef } from '@polkadot/react-hooks';
import { assert, isFunction } from '@polkadot/util';
import Button from './Button';
@ -16,6 +16,7 @@ import { useTranslation } from './translate';
function TxButton ({ accountId, className = '', extrinsic: propsExtrinsic, icon, isBasic, isBusy, isDisabled, isIcon, isToplevel, isUnsigned, label, onClick, onFailed, onSendRef, onStart, onSuccess, onUpdate, params, tooltip, tx, withSpinner, withoutLink }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const mountedRef = useIsMountedRef();
const { queueExtrinsic } = useContext(StatusContext);
const [isSending, setIsSending] = useState(false);
const [isStarted, setIsStarted] = useState(false);
@ -27,25 +28,27 @@ function TxButton ({ accountId, className = '', extrinsic: propsExtrinsic, icon,
const _onFailed = useCallback(
(result: SubmittableResult | null): void => {
setIsSending(false);
mountedRef.current && setIsSending(false);
onFailed && onFailed(result);
},
[onFailed, setIsSending]
[onFailed, setIsSending, mountedRef]
);
const _onSuccess = useCallback(
(result: SubmittableResult): void => {
setIsSending(false);
mountedRef.current && setIsSending(false);
onSuccess && onSuccess(result);
},
[onSuccess, setIsSending]
[onSuccess, setIsSending, mountedRef]
);
const _onStart = useCallback(
() => setIsStarted(true),
[setIsStarted]
(): void => {
mountedRef.current && setIsStarted(true);
},
[setIsStarted, mountedRef]
);
const _onSend = useCallback(
@ -72,9 +75,7 @@ function TxButton ({ accountId, className = '', extrinsic: propsExtrinsic, icon,
assert(extrinsics?.length, 'Expected generated extrinsic passed to TxButton');
if (withSpinner) {
setIsSending(true);
}
mountedRef.current && withSpinner && setIsSending(true);
extrinsics.forEach((extrinsic): void => {
queueExtrinsic({
@ -90,7 +91,7 @@ function TxButton ({ accountId, className = '', extrinsic: propsExtrinsic, icon,
onClick && onClick();
},
[_onFailed, _onStart, _onSuccess, accountId, api.tx, isUnsigned, onClick, onFailed, 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, mountedRef]
);
if (onSendRef) {

View File

@ -3,13 +3,25 @@
import { useCallback, useEffect, useState } from 'react';
import useIsMountedRef from './useIsMountedRef';
// Simple wrapper for a true/false toggle
export default function useToggle (defaultValue = false, onToggle?: (isActive: boolean) => void): [boolean, () => void, (value: boolean) => void] {
const mountedRef = useIsMountedRef();
const [isActive, setActive] = useState(defaultValue);
const toggleActive = useCallback(
() => setActive((isActive: boolean) => !isActive),
[]
const _toggleActive = useCallback(
(): void => {
mountedRef.current && setActive((isActive) => !isActive);
},
[mountedRef]
);
const _setActive = useCallback(
(isActive: boolean): void => {
mountedRef.current && setActive(isActive);
},
[mountedRef]
);
useEffect(
@ -17,5 +29,5 @@ export default function useToggle (defaultValue = false, onToggle?: (isActive: b
[isActive, onToggle]
);
return [isActive, toggleActive, setActive];
return [isActive, _toggleActive, _setActive];
}