// @flow import React from 'react'; // UTILS import { formatGasLimit } from 'utils/formatters'; import translate from 'translations'; import pickBy from 'lodash/pickBy'; // SELECTORS import { getNodeConfig } from 'selectors/config'; import { getNodeLib, getNetworkConfig, getGasPriceGwei } from 'selectors/config'; import { getTokenBalances, getTxFromBroadcastTransactionStatus } from 'selectors/wallet'; import { getTokens } from 'selectors/wallet'; import type { TokenBalance } from 'selectors/wallet'; // COMPONENTS import { UnlockHeader } from 'components/ui'; import { Donate, DataField, CustomMessage, GasField, AmountField, AddressField, ConfirmationModal } from './components'; import { BalanceSidebar } from 'components'; // CONFIG import type { NodeConfig } from 'config/data'; import type { Token, NetworkConfig } from 'config/data'; import { donationAddressMap } from 'config/data'; // REDUX import { connect } from 'react-redux'; import type { State as AppState } from 'reducers'; import { broadcastTx } from 'actions/wallet'; import type { BroadcastTxRequestedAction } from 'actions/wallet'; import { showNotification } from 'actions/notifications'; import type { ShowNotificationAction } from 'actions/notifications'; // LIBS import BaseWallet from 'libs/wallet/base'; import { isValidETHAddress } from 'libs/validators'; import type { RPCNode } from 'libs/nodes'; import type { BroadcastTransactionStatus, TransactionInput, CompleteTransaction } from 'libs/transaction'; import type { TransactionWithoutGas } from 'libs/messages'; import type { UNIT } from 'libs/units'; import { toWei } from 'libs/units'; import { generateCompleteTransaction, getBalanceMinusGasCosts, formatTxInput } from 'libs/transaction'; // MISC import customMessages from './messages'; import Big from 'bignumber.js'; type State = { hasQueryString: boolean, readOnly: boolean, to: string, // amount value value: string, // $FlowFixMe - Comes from getParam not validating unit unit: UNIT, token: ?Token, gasLimit: string, data: string, gasChanged: boolean, transaction: ?CompleteTransaction, showTxConfirm: boolean, generateDisabled: boolean }; function getParam(query: { [string]: string }, key: string) { const keys = Object.keys(query); const index = keys.findIndex(k => k.toLowerCase() === key.toLowerCase()); if (index === -1) { return null; } return query[keys[index]]; } type Props = { location: { query: { [string]: string } }, wallet: BaseWallet, balance: Big, node: NodeConfig, nodeLib: RPCNode, network: NetworkConfig, tokens: Token[], tokenBalances: TokenBalance[], gasPrice: string, broadcastTx: (signedTx: string) => BroadcastTxRequestedAction, showNotification: ( level: string, msg: string, duration?: number ) => ShowNotificationAction, transactions: Array }; const initialState = { hasQueryString: false, readOnly: false, to: '', value: '', unit: 'ether', token: null, gasLimit: '21000', data: '', gasChanged: false, showTxConfirm: false, transaction: null, generateDisabled: true }; export class SendTransaction extends React.Component { props: Props; state: State = initialState; componentDidMount() { const queryPresets = pickBy(this.parseQuery()); if (Object.keys(queryPresets).length) { this.setState({ ...queryPresets, hasQueryString: true }); } } componentDidUpdate(_prevProps: Props, prevState: State) { // TODO listen to gas price changes here // TODO debounce the call if ( // if gas has not changed !this.state.gasChanged && // if we have valid tx this.isValid() && // if any relevant fields changed (this.state.to !== prevState.to || this.state.value !== prevState.value || this.state.unit !== prevState.unit || this.state.data !== prevState.data) ) { if (!isNaN(parseInt(this.state.value))) { this.estimateGas(); } } if (this.state.generateDisabled === this.isValid()) { this.setState({ generateDisabled: !this.isValid() }); } const componentStateTransaction = this.state.transaction; if (componentStateTransaction) { // lives in redux state const currentTxAsSignedTransaction = getTxFromBroadcastTransactionStatus( this.props.transactions, componentStateTransaction.signedTx ); // if there is a matching tx in redux state if (currentTxAsSignedTransaction) { // if the broad-casted transaction attempt is successful, clear the form if (currentTxAsSignedTransaction.successfullyBroadcast) { this.resetTx(); } } } } render() { const unlocked = !!this.props.wallet; const { to, value, unit, gasLimit, data, readOnly, hasQueryString, showTxConfirm, transaction } = this.state; const customMessage = customMessages.find(m => m.to === to); return (
{/* Send Form */} {unlocked &&
{hasQueryString &&

{translate('WARN_Send_Link')}

} !token.balance.eq(0)) .map(token => token.symbol) .sort()} onChange={readOnly ? void 0 : this.onAmountChange} /> {unit === 'ether' && }
{transaction &&