diff --git a/packages/app-contracts/src/Contracts/Call.tsx b/packages/app-contracts/src/Contracts/Call.tsx index 2dc3d6c9ef..6125118e4f 100644 --- a/packages/app-contracts/src/Contracts/Call.tsx +++ b/packages/app-contracts/src/Contracts/Call.tsx @@ -3,311 +3,273 @@ // of the Apache-2.0 license. See the LICENSE file for details. import { ApiProps } from '@polkadot/react-api/types'; -import { BareProps, I18nProps } from '@polkadot/react-components/types'; +import { BareProps, CallContract, I18nProps, StringOrNull } from '@polkadot/react-components/types'; +import { QueueProps } from '@polkadot/react-components/Status/types'; +import { ContractExecResult } from '@polkadot/types/interfaces/contracts'; import BN from 'bn.js'; -import React from 'react'; -import { RouteComponentProps } from 'react-router'; -import { withRouter } from 'react-router-dom'; -import { Abi } from '@polkadot/api-contract'; -import { Button, Dropdown, InputAddress, InputBalance, InputNumber, Modal, TxButton, TxComponent } from '@polkadot/react-components'; -import { getContractAbi } from '@polkadot/react-components/util'; +import React, { useState } from 'react'; +import rpc from '@polkadot/jsonrpc'; +import { Button, Dropdown, InputAddress, InputBalance, InputNumber, Modal, Output, TxButton } from '@polkadot/react-components'; +import { QueueConsumer } from '@polkadot/react-components/Status/Context'; import { withApi, withMulti } from '@polkadot/react-api'; -import { displayType } from '@polkadot/types'; +import { isNull, isUndefined } from '@polkadot/util'; + +import Params from '../Params'; import translate from '../translate'; -import Params from '../Params'; import { GAS_LIMIT } from '../constants'; +import { findCallMethod, getContractForAddress, getCallMethodOptions, getContractMethodFn } from './util'; -interface Props extends BareProps, I18nProps, ApiProps, RouteComponentProps<{}> { - address: string | null; +interface Props extends BareProps, I18nProps, ApiProps { + callContract: CallContract | null; + callMethodIndex: number | null; isOpen: boolean; - method: string | null; + onChangeCallContract: (callContract: CallContract) => void; + onChangeCallMethodIndex: (callMethodIndex: number) => void; onClose: () => void; } -interface State { - accountId: string | null; - address: string | null; - contractAbi?: Abi | null; - endowment: BN; - gasLimit: BN; - isAddressValid: boolean; - isBusy: boolean; - method: string | null; - params: any[]; -} +function Call (props: Props): React.ReactElement | null { + const { isOpen, callContract, callMethodIndex, onChangeCallContract, onChangeCallMethodIndex, onClose, api, t } = props; -class Call extends TxComponent { - public defaultState: State = { - address: null, - accountId: null, - endowment: new BN(0), - gasLimit: new BN(GAS_LIMIT), - method: null, - isAddressValid: false, - isBusy: false, - params: [] + if (isNull(callContract) || isNull(callMethodIndex)) { + return null; + } + + const hasRpc = api.rpc.contracts && api.rpc.contracts.call; + const callMethod = findCallMethod(callContract, callMethodIndex); + const useRpc = hasRpc && callMethod && !callMethod.mutates; + // const isRpc = false; + + const [accountId, setAccountId] = useState(null); + const [endowment, setEndowment] = useState(new BN(0)); + const [gasLimit, setGasLimit] = useState(new BN(GAS_LIMIT)); + const [isBusy, setIsBusy] = useState(false); + const [params, setParams] = useState([]); + + const _onChangeAccountId = (accountId: StringOrNull): void => setAccountId(accountId); + + const _onChangeCallAddress = (callAddress: StringOrNull): void => { + const callContract = getContractForAddress(callAddress); + + onChangeCallContract && callContract.abi && onChangeCallContract(callContract); }; - public state: State = this.defaultState; + const _onChangeCallMethodString = (callMethodString: string): void => { + setParams([]); + onChangeCallMethodIndex && onChangeCallMethodIndex(parseInt(callMethodString, 10) || 0); + }; - public static getDerivedStateFromProps ({ address: propsAddress, method: propsMethod, isOpen }: Props, { address, method }: State): Pick | null { - if (!isOpen) { - return { - address: null, - method: null, - contractAbi: null, - isAddressValid: false - }; - } + const _onChangeEndowment = (endowment?: BN): void => endowment && setEndowment(endowment); + const _onChangeGasLimit = (gasLimit?: BN): void => gasLimit && setGasLimit(gasLimit); - return { - ...( - !address - ? { - address: propsAddress, - contractAbi: propsAddress ? getContractAbi(propsAddress) : null, - isAddressValid: !!propsAddress - } - : {} - ), - ...( - !method - ? { method: propsMethod } - : {} - ) - }; - } + const _onChangeParams = (params: any[]): void => setParams(params); + const _toggleBusy = (): void => setIsBusy(!isBusy); - public render (): React.ReactNode { - const { isOpen, t } = this.props; - - return ( - - - {t('Call a contract')} - - - {this.renderContent()} - - - {this.renderButtons()} - - - ); - } - - public renderContent (): React.ReactNode { - const { t } = this.props; - const { gasLimit } = this.state; - - const [address, contractAbi, method] = this.getCallProps(); - const isEndowValid = true; - const isGasValid = gasLimit.gtn(0); - - if (!address || !contractAbi) { - return null; - } - - const methodOptions = contractAbi - ? Object.keys(contractAbi.messages).map((key): { key: string; text: string; value: string } => { - const fn = contractAbi.messages[key]; - const type = fn.type ? `: ${displayType(fn.type)}` : ''; - const args = fn.args.map(({ name, type }): string => `${name}: ${displayType(type)}`); - const text = `${key}(${args.join(', ')})${type}`; - - return { - key, - text, - value: key - }; - }) - : []; - - return ( -
- - - - - - -
- ); - } - - private renderButtons (): React.ReactNode { - const { api, t } = this.props; - const { accountId, gasLimit, isAddressValid } = this.state; - const isEndowValid = true; // !endowment.isZero(); - const isGasValid = !gasLimit.isZero(); - const isValid = !!accountId && isEndowValid && isGasValid && isAddressValid; - - return ( - -