import React, { Component } from 'react'; import translate from 'translations'; import './InteractExplorer.scss'; import { TShowNotification, showNotification } from 'actions/notifications'; import { getNodeLib } from 'selectors/config'; import { getTo, getDataExists } from 'selectors/transaction'; import { GenerateTransaction } from 'components/GenerateTransaction'; import { AppState } from 'reducers'; import { connect } from 'react-redux'; import { Fields } from './components'; import { setDataField, TSetDataField } from 'actions/transaction'; import { Data } from 'libs/units'; import { Web3Node } from 'libs/nodes'; import RpcNode from 'libs/nodes/rpc'; import { Input } from 'components/ui'; import Dropdown from 'components/ui/Dropdown'; interface StateProps { nodeLib: RpcNode | Web3Node; to: AppState['transaction']['fields']['to']; dataExists: boolean; } interface DispatchProps { showNotification: TShowNotification; setDataField: TSetDataField; } interface OwnProps { contractFunctions: any; } type Props = StateProps & DispatchProps & OwnProps; interface State { inputs: { [key: string]: { rawData: string; parsedData: string[] | string }; }; outputs: any; selectedFunction: null | ContractOption; } interface ContractFunction { constant: boolean; decodeInput: any; decodeOutput: any; encodeInput: any; inputs: any[]; outputs: any; } interface ContractOption { contract: ContractFunction; name: string; } class InteractExplorerClass extends Component { public static defaultProps: Partial = { contractFunctions: {} }; public state: State = { selectedFunction: null, inputs: {}, outputs: {} }; public render() { const { inputs, outputs, selectedFunction } = this.state; const contractFunctionsOptions = this.contractOptions(); const { to } = this.props; const generateOrWriteButton = this.props.dataExists ? ( ) : ( ); return (
); } private contractOptions = () => { const { contractFunctions } = this.props; const transformedContractFunction: ContractOption[] = Object.keys(contractFunctions).map( contractFunction => { const contract = contractFunctions[contractFunction]; return { name: contractFunction, contract }; } ); return transformedContractFunction; }; private handleFunctionCall = async (_: React.FormEvent) => { try { const data = this.encodeData(); const { nodeLib, to } = this.props; const { selectedFunction } = this.state; if (!to.value) { throw Error(); } const callData = { to: to.raw, data }; const results = await nodeLib.sendCallRequest(callData); const parsedResult = selectedFunction!.contract.decodeOutput(results); this.setState({ outputs: parsedResult }); } catch (e) { this.props.showNotification( 'warning', `Function call error: ${(e as Error).message}` || 'Invalid input parameters', 5000 ); } }; private handleFunctionSend = (_: React.FormEvent) => { try { const data = this.encodeData(); this.props.setDataField({ raw: data, value: Data(data) }); } catch (e) { this.props.showNotification( 'danger', `Function send error: ${(e as Error).message}` || 'Invalid input parameters', 5000 ); } }; private handleFunctionSelect = (selectedFunction: ContractOption) => { this.setState({ selectedFunction, outputs: {}, inputs: {} }); }; private encodeData(): string { const { selectedFunction, inputs } = this.state; const parsedInputs = Object.keys(inputs).reduce( (accu, key) => ({ ...accu, [key]: inputs[key].parsedData }), {} ); return selectedFunction!.contract.encodeInput(parsedInputs); } private tryParseJSON(input: string) { try { return JSON.parse(input); } catch { return input; } } private handleInputChange = (ev: React.FormEvent) => { const rawValue: string = ev.currentTarget.value; const isArr = rawValue.startsWith('[') && rawValue.endsWith(']'); const value = { rawData: rawValue, parsedData: isArr ? this.tryParseJSON(rawValue) : rawValue }; this.setState({ inputs: { ...this.state.inputs, [ev.currentTarget.name]: value } }); }; } export const InteractExplorer = connect( (state: AppState) => ({ nodeLib: getNodeLib(state), to: getTo(state), dataExists: getDataExists(state) }), { showNotification, setDataField } )(InteractExplorerClass);